question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

CosmosDB's Bulk Upsert Responds with 400

See original GitHub issue
  • Package Name: @azure/cosmos
  • Package Version: 3.9.5
  • Operating system: WSL Ubuntu 18.04
  • nodejs
    • version: 10.23.3
  • browser
    • name/version:
  • typescript
    • version: 4.2.3
  • Is the bug related to documentation in

Describe the bug Using the bulk upsert option in a manner similar to what is proposed in #14128 (thanks for showing this!) fails for upsert.

To Reproduce Steps to reproduce the behavior:

  1. Set up some code like:
const { database } = await client.databases
      .createIfNotExists({ id: someDatabaseName });
const { container } = await client
      .database(database.id)
      .containers.createIfNotExists({ id: someContainerName, partitionKey: chosenPartition }); //partitionKey in this example was "/key"
//...
const operations = [
                {
                     operationType: azcosmos.BulkOperationType.Create,
                     resourceBody: {  "name": "somethingelse", "key": "A" }
                },
                {
                    operationType: azcosmos.BulkOperationType.Upsert,
                    partitionKey: "U",
                    resourceBody: { "name": "other1", "key": "U" }
                },
            ];
console.log(operations);
const response = await container.items.bulk(operations);
console.log(response);
  1. Run this code.
  2. See the response:
[ { statusCode: 201,
    requestCharge: 6.285714285714286,
    eTag: '"someEtag"',
    resourceBody:
     { name: 'somethingelse',
       key: 'A',
       id: 'some-uuid',
       _rid: '...',
       _self: '...',
       _etag: '"..."',
       _attachments: '...',
       _ts: ... } },
  { statusCode: 400, requestCharge: 0 } ]

Expected behavior If this fails for a 400 reason, I would love to know specifically which one. The options listed in the docs don’t seem to apply in my case, but it’s hard to tell what it’s failing for if that’s not bubbled up with the status code. Even more ideal is not getting a 400 at all. Creating and reading work as expected, but FWIW I haven’t checked deleting.

Based on the source code, I’d make a few assumptions:

  • the inclusion of the partition key is an optional argument based on the definition
    • In the case of not including it, the result that I got was still a 400
  • because Cosmos DB is schema-less, I would theoretically be able to have the example operations have different contents inside.
    • On the portal if an item is added without the partition key, there is no fuss.
    • If I change the contents to something arbitrary:
const operations: [
            {
                operationType: azcosmos.BulkOperationType.Create,
                resourceBody: { "name": "somethingelse", "key": "A" }
            },
            {
                operationType: azcosmos.BulkOperationType.Upsert,
                partitionKey: "U",
                resourceBody: { "name": "other1", "toot": "turtle" }
            },
    ]

… the typescript will not compile:

⨯ Unable to compile TypeScript:
index.ts:159:53 - error TS2345: Argument of type '({ operationType: "Create"; resourceBody: { name: string; key: string; toot?: undefined; }; partitionKey?: undefined; } | { operationType: "Upsert"; partitionKey: string; resourceBody: { name: string; toot: string; key?: undefined; }; })[]' is not assignable to parameter of type 'OperationInput[]'.
  Type '{ operationType: "Create"; resourceBody: { name: string; key: string; toot?: undefined; }; partitionKey?: undefined; } | { operationType: "Upsert"; partitionKey: string; resourceBody: { name: string; toot: string; key?: undefined; }; }' is not assignable to type 'OperationInput'.
    Type '{ operationType: "Create"; resourceBody: { name: string; key: string; toot?: undefined; }; partitionKey?: undefined; }' is not assignable to type 'OperationInput'.
      Type '{ operationType: "Create"; resourceBody: { name: string; key: string; toot?: undefined; }; partitionKey?: undefined; }' is not assignable to type 'CreateOperationInput'.
        Types of property 'resourceBody' are incompatible.
          Type '{ name: string; key: string; toot?: undefined; }' is not assignable to type 'JSONObject'.
            Property '"toot"' is incompatible with index signature.
              Type 'undefined' is not assignable to type 'JSONValue'.

159         const response = await container.items.bulk(operations);

… which seemingly is failing on the “create” Operation. It’s a bit confusing since the create operation wasn’t what was changed.

Screenshots If applicable, add screenshots to help explain your problem.

Additional context It would be great to have documentation about the different acceptable ways to perform operations given specific data. If Upsert expects a resourceBody to look either like XYZ or ABC, and Create expects QRS only, etc . In the signature would be fine but even better would be in the docs.

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Comments:6 (5 by maintainers)

github_iconTop GitHub Comments

1reaction
zfostercommented, Mar 11, 2021

release 3.10.2 should autogenerate IDs for Upsert operations in bulk now

1reaction
zfostercommented, Mar 10, 2021

@mindlessroman The 400 error is caused by this PR not being released yet - I kicked off a release but it failed and didn’t rerun it, I’ll get that out now. Unfortunately, we only get the response codes back from bulk failures.

As for the compilation failures when you use “toot”, that seems to either be from an old build or from the type being wrong.

Type '{ name: string; key: string; toot?: undefined; }' is not assignable to type 'JSONObject'.

The type on the left above doesn’t seem like what you actually want it to be (feel free to import OperationInput as a type and use that). In my experimenting, the body I pass to container.items.upsert() works for the resourceBody of bulk. I think it’s the same issue with the type not matching what bulk expects. I have a working test case that uses “toot” as a key

Read more comments on GitHub >

github_iconTop Results From Across the Web

Cosmos bulk insertion does not return success. Response ...
Cosmos bulk insertion does not return success. Response status code does not indicate success: BadRequest (400); Substatus: 0; Reason: ();.
Read more >
Troubleshoot Azure Cosmos DB bad request exceptions
The HTTP status code 400 represents the request contains invalid data or it's missing required parameters. Missing the ID property. On this ...
Read more >
[CosmosDB] Bulk Upsert not creating resourceBody Id for you
[CosmosDB] Bulk Upsert not creating resourceBody Id for you #13621 ; Client This issue points to a problem in the data-plane of the...
Read more >
Azure Cosmos DB 4xx Status Codes - Blue Matador
The nature of Cosmos DB means that sometimes requests will return HTTP status codes in the 400 range when operations do not succeed....
Read more >
How to efficiently write millions of records in the cloud and not ...
I created the most naive implementation of a batch update process. ... Luckily, every response from Cosmos DB contains the operation's cost ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found