Google Tasks API BatchRequest triggers "Duplicate Request ID in Batch Request"

690 Views Asked by At

Starting Sept 13th the Google Tasks BatchRequest update workflow is triggering a 400 error return "Duplicate Request ID in Batch Request" within an application that has remained stable for years. I can't find anything in the request that indicates a duplicate request id. Anyone have any idea what's up? Did Google change something?

Here's a copy of the response I'm receiving when sending a simple batch task insert request ...

[{
  "error": {
    "code": 400,
    "message": "Duplicate Request ID in Batch Request: ",
    "errors": [
      {
        "message": "Duplicate Request ID in Batch Request: ",
        "domain": "global",
        "reason": "badRequest"
      }
    ],
    "status": "INVALID_ARGUMENT"
  }
}]

UPDATE

While investigating this issue I found that Google made a change that now requires the Content-ID header on each batch request item. This header is currently not set when using the .Net Google.Apis.Requests.BatchRequest class.

To work around this I was able to create a new local implementation of Google.Apis.Requests.BatchRequest and inject a "Content-ID" header then creating each request entry.

private static long _id = 0;

[VisibleForTestOnly]
internal static async Task<HttpContent> CreateIndividualRequest(IClientServiceRequest request)
{
    HttpRequestMessage requestMessage = request.CreateRequest(false);
    string requestContent = await CreateRequestContentString(requestMessage).ConfigureAwait(false);

    var content = new StringContent(requestContent);
    content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/http");
    content.Headers.Add("Content-ID", (_id++).ToString());
    return content;
}
3

There are 3 best solutions below

2
On

Update 2021/09/28:

This issue has been marked as fixed and you shouldn't be experiencing this anymore:

Thank you for your patience, as of now this issue is fixed. If this issue persists let us know in a comment so we can assist you.

Original answer:

This doesn't seem to be limited to the library, nor to Tasks API, since it's happening at least in Calendar API too.

Now the batch endpoints seem to require Content-ID to be provided in the request, so it has to be added manually if the library doesn't do it.

It's still not clear whether this is an expected change of behavior or not.

It has been reported in the .NET library GitHub:

And also in Google Issue Tracker:

I'd suggest starring the referenced issue in Issue Tracker in order to help prioritizing it (if this is an expected behavior, at least it should be mentioned in the documentation that Content-ID has to be provided).

6
On

Thank you for sorting this out! The Content-ID header solves the problem.

But instead of creating a new implementation of Google.Apis.Requests.BatchRequest you can inject a HttpExecuteInterceptor into the underlying service which is then called by the batch request.

Create the interceptor:

public class GoogleBatchInterceptor : IHttpExecuteInterceptor
{
    public Task InterceptAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        if (request.Content is not MultipartContent multipartContent)
        {
            return Task.CompletedTask;
        }
        
        foreach (var content in multipartContent)
        {
            content.Headers.Add("Content-ID", Guid.NewGuid().ToString());
        }

        return Task.CompletedTask;
    }
}

Add the interceptor to the service:

CalendarService calendarService = CreateTheCalendarService();
calendarService.HttpClient.MessageHandler.AddExecuteInterceptor(new GoogleBatchInterceptor());
0
On

I can confirm this was an unintended issue on the backend side which affected the Calendar and Tasks APIs batch endpoint.

A fix has been fully rolled out and both endpoints should be working as before, i.e. ContentID is not required for batched requests. For those of you who put patches or workarounds in place, you may remove them.

Also, you may follow https://github.com/googleapis/google-api-dotnet-client/issues/1969, specially if you have questions/related issues.