CS-10103: clamp error_doc on persistence to dodge jsonb 256 MiB array limit#4564
Merged
CS-10103: clamp error_doc on persistence to dodge jsonb 256 MiB array limit#4564
Conversation
`clampSerializedError` is a no-op for any error_doc that already serializes under 8 MiB. When a doc would exceed the budget — almost always because dep-error fan-out has accumulated a deep `additionalErrors` tree across many indexing cycles — it sheds structure progressively (per-entry stacks → top-level stack → per-entry messages → nested additionalErrors → entry count cap → drop additionalErrors → envelope shrink), stopping as soon as the doc fits. Wired in at the IndexWriter and modules-cache write paths so every error row passes through it. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Contributor
There was a problem hiding this comment.
Pull request overview
Adds a persistence-layer safety net to prevent oversized error_doc JSONB writes from failing due to Postgres’s jsonb array element-size limit, by clamping serialized errors right before they’re written to the database.
Changes:
- Introduces
clampSerializedError()(with exported size/entry-count constants) to progressively shedSerializedError.additionalErrors/stack/message data until under an 8 MiB budget. - Applies the clamp at the two main persistence chokepoints: index writer error-doc writes and module cache error-doc writes.
- Adds unit + integration test coverage to verify pass-through behavior when under budget and progressive shedding when over budget.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/runtime-common/index.ts | Re-exports the new clamp function and related constants for consumers. |
| packages/runtime-common/index-writer.ts | Clamps normalized error docs immediately before persistence to boxel_index.error_doc. |
| packages/runtime-common/error.ts | Implements clampSerializedError() and defines size/entry limits + sentinel behavior. |
| packages/runtime-common/definition-lookup.ts | Clamps modules.error_doc.error before JSON serialization to the DB cache. |
| packages/realm-server/tests/index.ts | Registers the new clamp unit test file in the realm-server test suite. |
| packages/realm-server/tests/clamp-serialized-error-test.ts | Adds focused unit tests for each progressive shedding step and no-mutation behavior. |
| packages/host/tests/unit/index-writer-test.ts | Adds integration tests ensuring IndexWriter persists in-budget errors verbatim and sheds oversized ones. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Addresses two PR review comments on the clamp: 1. Step 5 now keeps `MAX-1` real entries plus one sentinel, so the final array length equals `ERROR_DOC_MAX_ADDITIONAL_ERRORS` — the constant name and the resulting length agree. 2. Capture `originalAdditionalCount` once at the top so both step 5's and step 6's sentinels report the *original* count, not whatever the array length happens to be after a prior step. Adds a step-6 assertion that the lone sentinel reports the original count (otherwise step 6 would silently report `MAX` instead of the real number that got dropped). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Contributor
Preview deployments |
Contributor
Contributor
backspace
approved these changes
Apr 29, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes CS-10103 — the production Sentry where
boxel_index.error_docupserts fail withtotal size of jsonb array elements exceeds the maximum of 268435455 bytes. Postgres jsonb stores child offsets in 28 bits, so a single jsonb array's elements must total < 256 MiB — that's a format-level constraint baked into jsonb, not a column setting we can raise.The triggering pattern in production: dependency-error fan-out repeatedly copies each dep row's full
error_doc(nestedadditionalErrorsand all) into its parent during indexing. Across many indexing cycles in a realm with chained errors, theadditionalErrorstree compounds without bound and eventually hits the jsonb limit on upsert.What this changes
clampSerializedErrorinruntime-common/error.ts. It is the chokepoint that runs on everyerror_docgoing into the database (bothboxel_index.error_docviaIndexWriter.normalizeErrorDocandmodules.error_docviaCachingDefinitionLookup.writeToDatabaseCache).ERROR_DOC_MAX_BYTES(8 MiB — 32× under the jsonb limit), the input is returned unchanged. Nothing is dropped.additionalErrors[i].stackto ~64 KiBstackto ~64 KiBadditionalErrors[i].messageto ~16 KiBadditionalErrorsof inherited entries (drop only the second level of nesting)additionalErrorsentirely with a sentinel — last resortstack/messageif even the bare envelope is still too bigid,status,title,deps,source,diagnostics,isCardErrorare never touched — they're scalars/small.The dep-error propagation paths in
index-runner/index-backed-dependency-errors.tsanddefinition-lookup.tsare intentionally unchanged — preserving full additionalErrors trees for debug visibility was a hard requirement. The clamp is a safety net at the persistence layer, not a routine truncation in the propagators.Test plan
clamp-serialized-error-test.ts— 10 unit tests, one per shedding step, each asserting that only the targeted step ran (later steps left the doc alone). Verifies pass-through for in-budget docs and no-mutation of the input.index-writer-test.ts— 2 integration tests: one verifying an in-budget error_doc is persisted verbatim through the IndexWriter, one verifying an oversized doc is shed progressively until it fits.pnpm lintclean forruntime-common,realm-server,host.🤖 Generated with Claude Code