Skip to content

fix(client): fix browser-imported Prisma.DbNull producing empty object#29286

Merged
jacek-prisma merged 8 commits intoprisma:mainfrom
Not-Sarthak:fix/browser-dbnull-cross-bundle
Mar 9, 2026
Merged

fix(client): fix browser-imported Prisma.DbNull producing empty object#29286
jacek-prisma merged 8 commits intoprisma:mainfrom
Not-Sarthak:fix/browser-dbnull-cross-bundle

Conversation

@Not-Sarthak
Copy link
Copy Markdown
Contributor

@Not-Sarthak Not-Sarthak commented Mar 2, 2026

Summary

Fixes #29257

When importing Prisma.DbNull from the browser entry point (./generated/prisma/browser) and passing it to prisma.create() in a bundled environment like Next.js, the value is serialized as {} instead of NULL.

Root cause: The serialization code uses instanceof ObjectEnumValue to detect DbNull/JsonNull/AnyNull values. In bundled environments (e.g., Next.js with webpack/turbopack), the browser and server entry points may resolve to separate copies of @prisma/client-runtime-utils, creating different class instances. The instanceof check fails across these bundle boundaries, causing DbNull to fall through to the generic object serialization path and become {}.

Fix: Replace all instanceof ObjectEnumValue checks with a new isObjectEnumValue() duck-typing function that checks for the _getName and _getNamespace methods. This follows the existing isDecimalJsLike pattern already used in the codebase for cross-bundle Decimal detection.

Changes

  • client-runtime-utils/src/nullTypes.ts: Add isObjectEnumValue() duck-typing function
  • client/src/runtime/index-browser.ts: Export isObjectEnumValue
  • client/src/runtime/index.ts: Export isObjectEnumValue
  • client/src/runtime/core/jsonProtocol/serializeJsonQuery.ts: Use isObjectEnumValue() instead of instanceof ObjectEnumValue; validate by name string instead of singleton identity
  • client/src/runtime/utils/deepCloneArgs.ts: Use isObjectEnumValue() instead of instanceof ObjectEnumValue
  • client/src/runtime/core/errorRendering/ArgumentsRenderingTree.ts: Use isObjectEnumValue() instead of instanceof ObjectEnumValue

Test plan

  • All 57 serializeJsonQuery tests pass
  • All 4 deepCloneArgs tests pass
  • All 24 ArgumentsRenderingTree tests pass
  • ESLint: 0 errors
  • Pre-commit hooks pass (prettier + eslint)

Summary by CodeRabbit

  • New Features

    • Added a public utility to reliably detect object enum values across bundle boundaries and exported it from the runtime.
  • Bug Fixes

    • Improved detection and serialization of object enum/null-like values coming from other bundles, preventing incorrect stringification or validation errors.
  • Tests

    • Added tests covering cross-bundle enum/null detection, serialization, and preservation during deep-cloning.

…DbNull

Replace `instanceof ObjectEnumValue` checks with duck-typing via a new
`isObjectEnumValue()` function. This fixes Prisma.DbNull from the
browser entry point producing `{}` instead of NULL when passed to
PrismaClient in bundled environments like Next.js.

Fixes prisma#29257
@CLAassistant
Copy link
Copy Markdown

CLAassistant commented Mar 2, 2026

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you all sign our Contributor License Agreement before we can accept your contribution.
1 out of 2 committers have signed the CLA.

✅ jacek-prisma
❌ Not-Sarthak
You have signed the CLA already but the status is still pending? Let us recheck it.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 2, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Introduces a cross-bundle type guard isObjectEnumValue() in client-runtime-utils and replaces instanceof ObjectEnumValue checks with this guard across the client runtime; adds tests for cross-bundle null/enum serialization and cloning; re-exports the new guard in the public runtime index files.

Changes

Cohort / File(s) Summary
Core Type Guard
packages/client-runtime-utils/src/nullTypes.ts
Add PRISMA_OBJECT_ENUM_VALUE global symbol, expose readonly [PRISMA_OBJECT_ENUM_VALUE] = true on ObjectEnumValue and add exported isObjectEnumValue(value: unknown): value is ObjectEnumValue.
Runtime checks
packages/client/src/runtime/core/errorRendering/ArgumentsRenderingTree.ts, packages/client/src/runtime/core/jsonProtocol/serializeJsonQuery.ts, packages/client/src/runtime/utils/deepCloneArgs.ts
Replace instanceof ObjectEnumValue with isObjectEnumValue(value) and update imports to use the new guard; update enum-name extraction and null-handling in JSON serialization branch.
Public API exports
packages/client/src/runtime/index.ts, packages/client/src/runtime/index-browser.ts
Re-export isObjectEnumValue from @prisma/client-runtime-utils in both runtime entry points.
Serialization tests
packages/client/src/runtime/core/jsonProtocol/serializeJsonQuery.test.ts
Add makeCrossBundleNullValue() helper and three tests asserting correct serialization of cross-bundle DbNull/JsonNull/AnyNull as Enum values in JSON queries.
Cloning tests
packages/client/src/runtime/utils/deepCloneArgs.test.ts
Add test ensuring cross-bundle ObjectEnumValue instances (with Symbol.for('prisma.objectEnumValue')) are preserved (not cloned) by deepCloneArgs.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 40.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'fix(client): fix browser-imported Prisma.DbNull producing empty object' directly references the main issue: Prisma.DbNull from browser imports causing empty object serialization instead of NULL.
Linked Issues check ✅ Passed The pull request fully addresses issue #29257 by implementing cross-bundle ObjectEnumValue detection through a global symbol and the isObjectEnumValue() utility function, replacing instanceof checks that fail across bundle boundaries.
Out of Scope Changes check ✅ Passed All changes are directly scoped to fixing the cross-bundle ObjectEnumValue detection issue: new isObjectEnumValue() function, imports/exports, and updates to runtime checks in serialization and cloning utilities.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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 and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1


ℹ️ Review info

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6738298 and 2aba40d.

📒 Files selected for processing (6)
  • packages/client-runtime-utils/src/nullTypes.ts
  • packages/client/src/runtime/core/errorRendering/ArgumentsRenderingTree.ts
  • packages/client/src/runtime/core/jsonProtocol/serializeJsonQuery.ts
  • packages/client/src/runtime/index-browser.ts
  • packages/client/src/runtime/index.ts
  • packages/client/src/runtime/utils/deepCloneArgs.ts

@jacek-prisma
Copy link
Copy Markdown
Contributor

Thanks for the PR! The changes do not include any tests. Could you add a test based on the reported issue in packages/client/tests/e2e/?

Verifies DbNull, JsonNull, and AnyNull from the browser entry expose
_getName() and _getNamespace() methods used by isObjectEnumValue()
for duck-typing detection across bundle boundaries.
@Not-Sarthak
Copy link
Copy Markdown
Contributor Author

added a test in the existing browser-bundle e2e suite (c2c72b5) that verifies DbNull, JsonNull, and AnyNull from the browser entry expose _getName() and _getNamespace() — the duck-typing methods that isObjectEnumValue() relies on for cross-bundle detection.

couldn't run the e2e suite locally since it needs docker + tarball packing, but verified the underlying logic directly against the built runtime — isObjectEnumValue correctly identifies all three null types and works with cross-bundle instances where instanceof fails.

@jacek-prisma
Copy link
Copy Markdown
Contributor

I think the newly added test isn't sufficient, we need something that prevents future regression, ideally something that looks like a minimized reproduction of the original issue.

…tion

Simulates the cross-bundle scenario (e.g. Next.js bundling browser and
server code separately) by creating plain objects with the duck-typing
interface instead of real ObjectEnumValue instances.
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1


ℹ️ Review info

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c2c72b5 and 7e0ef5d.

📒 Files selected for processing (2)
  • packages/client/src/runtime/core/jsonProtocol/serializeJsonQuery.test.ts
  • packages/client/src/runtime/utils/deepCloneArgs.test.ts

@Not-Sarthak
Copy link
Copy Markdown
Contributor Author

i have updated the test

do correct me if i got something wrong, thanks for the review!

Replace duck-typing (_getName/_getNamespace method checks) with a
global symbol (Symbol.for('prisma.objectEnumValue')) for identifying
ObjectEnumValue instances across bundle boundaries. This is more
explicitly Prisma-specific and avoids false positives from unrelated
objects that happen to have similar methods.
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (1)
packages/client/src/runtime/core/jsonProtocol/serializeJsonQuery.test.ts (1)

795-880: ⚠️ Potential issue | 🟠 Major

Serializer snapshots are good, but please verify a true e2e persistence regression test exists.

These tests validate JSON protocol serialization, not the original failure mode (browser import + create() + DB persisted {} vs NULL). Please confirm an e2e test covers that exact flow.

#!/bin/bash
# Verify whether e2e tests cover browser-imported DbNull persistence to DB.
# Expected: at least one e2e test importing from browser entry and asserting persisted NULL behavior.

rg -nP -C3 --type=ts \
  "generated/prisma/browser|DbNull|JsonNull|AnyNull|create\(|json.*null|NULL" \
  packages/client/tests/e2e

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: c9c3962b-43d1-4c02-adf0-0540a01c04bf

📥 Commits

Reviewing files that changed from the base of the PR and between 7e0ef5d and 0e712a7.

📒 Files selected for processing (3)
  • packages/client-runtime-utils/src/nullTypes.ts
  • packages/client/src/runtime/core/jsonProtocol/serializeJsonQuery.test.ts
  • packages/client/src/runtime/utils/deepCloneArgs.test.ts

@jacek-prisma
Copy link
Copy Markdown
Contributor

There's a failing properties of DbNull/JsonNull/AnyNull › custom instances are not allowed as of latest changes

Custom ObjectEnumValue instances are now accepted because we use a
global symbol for detection instead of singleton equality checks.
This is necessary for cross-bundle support — a singleton from a
different bundle is indistinguishable from a custom instance.
@Not-Sarthak
Copy link
Copy Markdown
Contributor Author

fixed it, thanks for the review

@codspeed-hq
Copy link
Copy Markdown

codspeed-hq bot commented Mar 9, 2026

Merging this PR will degrade performance by 98.99%

⚠️ Different runtime environments detected

Some benchmarks with significant performance changes were compared across different runtime environments,
which may affect the accuracy of the results.

Open the report in CodSpeed to investigate

❌ 1 regressed benchmark
✅ 16 untouched benchmarks
⏩ 30 skipped benchmarks1

⚠️ Please fix the performance issues or acknowledge them on CodSpeed.

Performance Changes

Benchmark BASE HEAD Efficiency
compile blog post page (uncached baseline) 3.5 ms 346.1 ms -98.99%

Comparing Not-Sarthak:fix/browser-dbnull-cross-bundle (d840457) with main (7a1f497)

Open in CodSpeed

Footnotes

  1. 30 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

@jacek-prisma jacek-prisma merged commit 4b65b60 into prisma:main Mar 9, 2026
249 of 253 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Browser-imported 'Prisma.DBNull' create an empty object

3 participants