Skip to content

fix(client): handle batched findUniqueOrThrow misses#29654

Open
Shgit29 wants to merge 3 commits into
prisma:mainfrom
Shgit29:fix/29638-find-unique-or-throw-undefined
Open

fix(client): handle batched findUniqueOrThrow misses#29654
Shgit29 wants to merge 3 commits into
prisma:mainfrom
Shgit29:fix/29638-find-unique-or-throw-undefined

Conversation

@Shgit29

@Shgit29 Shgit29 commented Jun 24, 2026

Copy link
Copy Markdown

Problem

Concurrent findUniqueOrThrow() calls can be auto-batched by Prisma Client. When multiple records are missing in the same batch, only the first missing query rejects with P2025. Later missing queries can incorrectly resolve with undefined.

This happens because the multi-batch path in ClientEngine.requestBatch() stops collecting results after the first thrown error. As a result, the returned result array can be shorter than the original request batch, and DataLoader resolves the remaining slots as undefined.

Fixes #29638

Solution

Continue collecting results for auto-batched unique reads (findUnique / findUniqueOrThrow) outside explicit batch transactions. This preserves one result per request, so each missing findUniqueOrThrow() call rejects correctly with P2025.

Tests

Added a functional regression test for concurrent findUniqueOrThrow() calls with multiple missing records.

pnpm --filter @prisma/client test:functional:code --adapter js_pg --runInBand 29638-concurrent-find-unique-or-throw
@coderabbitai

coderabbitai Bot commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 4f5d28a9-cba1-4199-b5b7-9c95c3d9aab8

📥 Commits

Reviewing files that changed from the base of the PR and between 918cf5d and acfe533.

📒 Files selected for processing (4)
  • packages/client/src/runtime/core/engines/client/ClientEngine.ts
  • packages/client/tests/functional/issues/29638-concurrent-find-unique-or-throw/_matrix.ts
  • packages/client/tests/functional/issues/29638-concurrent-find-unique-or-throw/prisma/_schema.ts
  • packages/client/tests/functional/issues/29638-concurrent-find-unique-or-throw/tests.ts

Summary by CodeRabbit

  • Bug Fixes
    • Improved batch query handling so later operations can continue after an individual query failure in supported cases, while still preserving rollback behavior when needed.
  • Tests
    • Added coverage for concurrent findUniqueOrThrow behavior in a PostgreSQL-specific scenario.
    • Included a dedicated test setup and schema for the new functional case.

Walkthrough

ClientEngine.requestBatch gains a canContinueOnError flag that evaluates to true when the transaction is not of kind batch and every query action is findUnique or findUniqueOrThrow. The multi-query result loop, which previously broke unconditionally on the first error, now only breaks when canContinueOnError is false, allowing remaining queries to execute and record their own results or errors. A new PostgreSQL-only functional test suite is added for issue 29638, consisting of a test matrix, a three-model Prisma schema (User, Chat, ChatUser), and a test that seeds partial data and concurrently calls findUniqueOrThrow, asserting P2025 rejections for non-matching records.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main fix for batched findUniqueOrThrow misses.
Description check ✅ Passed The description accurately explains the bug, the fix, and the added regression test.
Linked Issues check ✅ Passed The code and test changes address the batched findUniqueOrThrow undefined-results bug, including concurrent and related-record queries.
Out of Scope Changes check ✅ Passed All changes are directly tied to the batching fix and its regression coverage.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
✨ Simplify code
  • Create PR with simplified code

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@Shgit29

Shgit29 commented Jun 26, 2026

Copy link
Copy Markdown
Author

Hi @aqrln, sorry for the direct tag.

This PR touches the ClientEngine.requestBatch() path, and I saw you worked on related Prisma Client runtime and batch request handling changes before.

The required workflows are still awaiting maintainer approval. Could you approve the workflow run, or route this to the right reviewer?

The targeted regression test passes locally with:

pnpm --filter @prisma/client test:functional:code --adapter js_pg --runInBand 29638-concurrent-find-unique-or-throw

Thanks!

Comment on lines 584 to 628
@@ -622,7 +626,9 @@ export class ClientEngine implements Engine {
} catch (err) {
results.push(err as Error)
rollback = true

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure it make sense to have the canContinueOnError being set outside the catch especially since we are processing a queries.every().

in the cases we do not catch an error it would process queries.every() pointlessly

Suggested change
let txInfo: InteractiveTransactionInfo | undefined
if (transaction?.kind === 'itx') {
// If we are already in an interactive transaction we do not nest transactions
} catch (err) {
const canContinueOnError =
transaction?.kind !== 'batch' &&
queries.every((query) => query.action === 'findUnique' || query.action === 'findUniqueOrThrow')
results.push(err as Error)
rollback = true
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

2 participants