Uh oh!
There was an error while loading. Please reload this page.
docs: MISSING_REQUIRED_FIELD answers 422 without fields on the surviving controlled_by_parent refusals - #8963
Merged
os-project-manager merged 1 commit intoAug 16, 2026
Conversation
…iving controlled_by_parent refusals (#8880) `MISSING_REQUIRED_FIELD` is documented as HTTP 400 carrying `fields[]` (`error-handling.mdx`, `error-catalog.mdx`), but `assertControlledByParentWrite` answers `422 MISSING_REQUIRED_FIELD` with no `fields[]` on four declarable shapes, plus a stored-row case on a different path. Documents the exception where it exists rather than moving the wire. Measured on this branch's base rather than taken from the card: - `resolveCbpRelation` sets `omissionRefusedByValidation` to `type === 'master_detail' && required && !readonly && !system`, so only that shape hands over to validation's `400 VALIDATION_FAILED`. - The four surviving shapes are pinned by `controlled-by-parent-sharing.test.ts` (`err.status`/`statusCode` 422). - `MasterReferenceMissingError` declares `code`/`status`/`statusCode`; `mapDataError`'s 4xx passthrough emits `{ error, code, object }`, and `fields[]` is emitted only for the `VALIDATION_FAILED` duck-type — so the absent `fields[]` is confirmed at the door, not assumed. One claim from the card and the #8879 changeset is deliberately NOT repeated: that a publish-time lint bounds these shapes. #8772 is still open and `relationship/master-detail-required` is `severity: 'warning'`, with no rule covering the `readonly`/`system`/fallback-`lookup` shapes — so the docs say these shapes are authorable today. Filed as #8959. No runtime change: the refusal is correct (an unconditional hand-over was measured fail-open) and direction 2 was declined by the maintainer ruling. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011RB4waLuNbdruCo6X9oobm
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
os-project-manager
marked this pull request as ready for review
August 16, 2026 03:10
os-project-manager
enabled auto-merge
August 16, 2026 03:10
This was referenced Aug 16, 2026
Uh oh!
There was an error while loading. Please reload this page.
os-project-manager
deleted the
claude/issue-8880-missing-required-field-status
branch
August 16, 2026 03:24
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 freeto 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.
Fixes#8880
Docs-only. Direction 1 of the card, per the maintainer ruling of 2026-08-15: the docs state the exception where it exists and name why the gate answers 422 there. No runtime edits — direction 2 (moving the wire to 400) was declined, and direction 3 (a catalog vs. runtime status conformance gate) stays its own card.
The mismatch, re-measured on this branch's base
MISSING_REQUIRED_FIELDis documented as HTTP 400 carryingfields, whileassertControlledByParentWriteanswers422 MISSING_REQUIRED_FIELDwith nofieldson four declarable shapes. I verified each half from source rather than taking the card's summary:The four shapes come from
resolveCbpRelation(packages/plugins/plugin-security/src/security-plugin.ts), which sets the one bit the stand-down turns on:So the hand-over to
400 VALIDATION_FAILEDhappens only for amaster_detailthat isrequiredand neitherreadonlynorsystem. The 422 survives for: amaster_detailwith norequired;required+readonly;required+system; and arequiredlookupresolved through the third fallback. All four are pinned incontrolled-by-parent-sharing.test.tsonerr.status/err.statusCode422. The stored-row case (an update or delete by id whose persisted FK is null) travels the non-insert branch and keeps the same envelope.The 422 and the absent
fieldsare confirmed at the door, not assumed.MasterReferenceMissingErrordeclarescode = 'MISSING_REQUIRED_FIELD',status = 422,statusCode = 422(errors.ts);declaredHttpStatusinpackages/rest/src/error-response.tsreadsstatusthenstatusCode, and its 4xx passthrough arm emits{ error, code, object }— nofields.fieldsis emitted only for theVALIDATION_FAILEDduck-type, which this error is not. Both halves of the card check out.One claim from the card that I did NOT repeat
The card, the landed #8879 changeset, and two source comments all state that #8772's publish-time lint refuses these shapes, "so newly authored metadata cannot reach them". That is not true today.#8772 is still open,
relationship/master-detail-requiredisseverity: 'warning'(packages/lint/src/data-model-rules.ts:491-499), and no rule covers thereadonly,system, or fallback-lookupshapes at all. Writing that bound into the docs would have documented a guarantee that does not exist, so the pages say instead that these shapes are authorable today. Filed separately as #8959 (sub-issue of #8772) — the stale claim is in landed source comments and a release-note-bound changeset, which is a runtime-adjacent fix and out of scope here.Related to the same honesty point: nothing mechanically pins either side of this branch, so both pages tell clients to branch on
codeand read the status off the response rather than deriving it from a table.Changes
content/docs/protocol/kernel/error-handling.mdx— theMISSING_REQUIRED_FIELDentry carries the exception, the full five-row matrix (which shape is refused by which subsystem, with status, code and whetherfieldsrides along), why the gate refuses rather than handing over (the measured fail-open alternative), and the authorable-today note. The 422 row of the HTTP status table now points at it.content/docs/api/error-catalog.mdx— the entry's "Checkfieldsfor the field name" line is qualified, aCalloutcarries the same exception in list form, and the status quick reference gains a 422 row marked as an exception to the 400 row rather than a second home for the code. The matrix itself lives in one place only (the protocol page, linked) — duplicating it across two files is the drift this card is about.Verification
Gate union run after the final commit, at
8ead907cd:Re-derived against the actual changed paths with
node scripts/pm/dispatch-gates.mjs— it returns exactlycheck:docs-audit-scopeandcheck:role-wordforcontent/docs, adding nothing;check:nul-bytesandcheck:error-code-casingwere run as the convention-scoped pair. No package builds or tests are implicated: no source file changed.Anchor and cross-doc link forms were checked against real precedents in the tree (
#letting-a-delegate-invite-delegated_adminconfirms underscores survive slugification;/docs/protocol/kernel/...confirms the cross-page path). The exception is rendered as a list rather than a table inside theCallout, since no existingCalloutincontent/docscontains a markdown table.skip-changeset: docs-only, nothing releasable.Generated by Claude Code