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.

Error with multiple upsert in $transaction

See original GitHub issue

Bug description

When I execute query, these two errors alternately appeared. One is ConnectorError and the other is Unique constraint error.

Second error is kind of strange, because I chose this approach(upsert with $transaction) to avoid race condition, but it seams like it is happened here. (I can verify that all names and userIds are unique.)

Maybe this is because some creation in $transaction is not broadcasted to others in $transaction, so creation can happen multiple time. (Now I remember I read something similar in docs)

Anyway, then what is the right way to do what I want? And what should I do for first error message?

Thank you.

Error: 
Invalid `prisma.tag.upsert()` invocation:


  Error occurred during query execution:
ConnectorError(ConnectorError { user_facing_error: None, kind: QueryError(Server(ServerError { code: 1213, message: "vttablet: rpc error: code = Aborted desc = (errno 1213) (sqlstate 40001) (CallerID: unsecure_grpc_client): Sql: \"insert into Tag(id, createdAt, updatedAt, `name`, userId) values (:v1, :v2, :v3, :v4, :v5)\", BindVars: {}", state: "40001" })) })
    at cb (/Users/yujonglee/dev/taggy.cloud/node_modules/@prisma/client/runtime/index.js:38692:17)
    at async Promise.all (index 0)
    at async createFile (/Users/yujonglee/dev/taggy.cloud/api/_build/index.js:1029:3)
    at async Promise.all (index 1)
    at async action3 (/Users/yujonglee/dev/taggy.cloud/api/_build/index.js:1202:3)
    at async Object.callRouteAction (/Users/yujonglee/dev/taggy.cloud/node_modules/@remix-run/server-runtime/data.js:36:14)
    at async handleDataRequest (/Users/yujonglee/dev/taggy.cloud/node_modules/@remix-run/server-runtime/server.js:110:18)
    at async requestHandler (/Users/yujonglee/dev/taggy.cloud/node_modules/@remix-run/server-runtime/server.js:45:20)
    at async /Users/yujonglee/dev/taggy.cloud/node_modules/@remix-run/express/server.js:45:22
Error: 
Invalid `prisma.tag.upsert()` invocation:


  Unique constraint failed on the (not available)
    at cb (/Users/yujonglee/dev/taggy.cloud/node_modules/@prisma/client/runtime/index.js:38688:17)
    at async Promise.all (index 0)
    at async createFile (/Users/yujonglee/dev/taggy.cloud/api/_build/index.js:1028:3)
    at async Promise.all (index 1)
    at async action3 (/Users/yujonglee/dev/taggy.cloud/api/_build/index.js:1201:3)
    at async Object.callRouteAction (/Users/yujonglee/dev/taggy.cloud/node_modules/@remix-run/server-runtime/data.js:36:14)
    at async handleDataRequest (/Users/yujonglee/dev/taggy.cloud/node_modules/@remix-run/server-runtime/server.js:110:18)
    at async requestHandler (/Users/yujonglee/dev/taggy.cloud/node_modules/@remix-run/server-runtime/server.js:45:20)
    at async /Users/yujonglee/dev/taggy.cloud/node_modules/@remix-run/express/server.js:45:22

How to reproduce

Just run query.

Expected behavior

For all strings in tagNames, create if not exist, in batch. (tagNames is array of string)

Prisma information

  await prisma.$transaction(tagNames.map((name) => (
    prisma.tag.upsert({
      where: {
        userId_name: {
          userId,
          name,
        },
      },
      create: {
        userId,
        name,
      },
      update: {},
    })
  )));
model Tag {
  id        String   @id @default(uuid())
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt

  name String

  User   User   @relation(fields: [userId], references: [id], onDelete: Cascade)
  userId String

  @@unique(fields: [userId, name])
}

Environment & setup

  • OS: Mac OS
  • Database: PlanetScale
  • Node.js version: 16.6.1

Prisma Version

prisma                  : 3.7.0
@prisma/client          : 3.7.0
Current platform        : darwin
Query Engine (Node-API) : libquery-engine 8746e055198f517658c08a0c426c7eec87f5a85f (at node_modules/@prisma/engines/libquery_engine-darwin.dylib.node)
Migration Engine        : migration-engine-cli 8746e055198f517658c08a0c426c7eec87f5a85f (at node_modules/@prisma/engines/migration-engine-darwin)
Introspection Engine    : introspection-core 8746e055198f517658c08a0c426c7eec87f5a85f (at node_modules/@prisma/engines/introspection-engine-darwin)
Format Binary           : prisma-fmt 8746e055198f517658c08a0c426c7eec87f5a85f (at node_modules/@prisma/engines/prisma-fmt-darwin)
Default Engines Hash    : 8746e055198f517658c08a0c426c7eec87f5a85f
Studio                  : 0.445.0
Preview Features        : referentialIntegrity

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Comments:7 (4 by maintainers)

github_iconTop GitHub Comments

1reaction
yujong-leecommented, Jan 11, 2022

@pantharshit00 I will do my best to reproduce this in minimal example and share it.

1reaction
hyochancommented, Jan 10, 2022

Did you try to create a row like below instead of direct insertion?

create: {
  user: {
    connect: {
      id: userId
    }
  }
},

I found this earlier that Prisma won’t naturally join the foreign key in such cases without connect. Would be great to organize this in an issue or document.

@yujong-lee I hope you try this out first and come back again.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Upsert with a transaction - sql
The problem is that, when there are many concurrent requests, this code fails with 'duplicate key' errors, meaning the transaction is not ...
Read more >
Please stop using this UPSERT anti-pattern
If the key exists and two sessions try to update simultaneously, they'll both update successfully (one will "win"; the "loser" will follow with ......
Read more >
Dublicate documents with transactions upsert
Hello. i use latest mongodb 5. Found intresting moment then update in parallel is not exists document with UPSERT by transaction i got ......
Read more >
Multiple upsert: Creating Parent and Child Records in a ...
1 Answer 1 ... For reasons I don't understand upsert does not support this pattern - as the error message explains insert ,...
Read more >
Salesforce Upsert Internal Error - Two Nodes Only
"Internal error, transaction node must have header and body node, two nodes only" What does this error mean, and what might be causing...
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