Skip to content

Commit 67ebc84

Browse files
docs(error-catalog): INVALID_FORMAT names what really checks a value (field type or a format rule) (#19878)
Fixes #19848 Clause-②: no ## What changed `content/docs/api/error-catalog.mdx` only. 1. **The `INVALID_FORMAT` entry.** Its **Fix** line told authors to match "the field's `format` constraint". No write-time check reads a field-level `format` key, so following that advice changes nothing. The entry now says what actually decides: - **No route emits the top-level `INVALID_FORMAT` today.** The entry now says so and tells clients to branch on `VALIDATION_FAILED` + `fields[].code`. That is the same shape the page's `INVALID_REFERENCE` entry already uses. - **The field `type`.** The built-in email / url / phone checks key on `type` and answer `invalid_email` / `invalid_url` / `invalid_phone`. Date and time parse failures answer `invalid_date` / `invalid_time`. - **A `format` validation rule** (a different key: its `regex` or its named `format` `email` | `url` | `phone` | `json`) answers field-level `invalid_format`. The link goes to `/docs/data-modeling/validation#format-validation`, the anchor PR #19847 uses. - Field-level `invalid_format` is also emitted for a missed declared `pattern` outside record metadata: a settings value, or a request body a route parses with Zod. - The Fix line now names the field `type` or the `format` validation rule as the things to change, and says a field-level `format` key runs no write-time check on any field type. 2. **A bounded in-place fix in the same file (declared here).** The `VALIDATION_ERROR` JSON example showed an email miss as `"code": "invalid_format"`. The Zod mapper answers `invalid_email` for that miss. See the Acceptance notes. The wording follows PR #19847 (still open at the time of writing; this PR depends on none of its files) and the spec's `format` describe: "keyed on `type`", "a field-level `format` key is not read", "a `format` validation rule". ## Evidence (all at base `2bbb4623`) | Claim | Where | |:---|:---| | Record validator never reads field `format`: `def.format` 0 hits, same-file control `def.type` 7 | `packages/objectql/src/validation/record-validator.ts` | | email / url / phone checks key on `type`, emit `invalid_email` / `invalid_url` / `invalid_phone` | `record-validator.ts:746-754` | | date / time parse failures emit `invalid_date` / `invalid_time` | `record-validator.ts:839`, `:858` | | A `format` validation rule (regex or named format) emits field-level `invalid_format` | `packages/objectql/src/validation/rule-validator.ts:2776-2790` (check), `:2822` (`formatViolation`) | | Settings `pattern` miss emits field-level `invalid_format` | `packages/services/service-settings/src/settings-service.ts:2042` | | Zod-parsed routes: email to `invalid_email`, url to `invalid_url`, other format/regex to `invalid_format` | `packages/spec/src/api/zod-issues-to-fields.ts:82-85` | | Top-level `INVALID_FORMAT` has no producer: `git grep INVALID_FORMAT` outside tests and `dist` hits only the enum member `packages/spec/src/api/errors.zod.ts:57`, the ADR note and the unpinned baseline | `scripts/error-status-unpinned-baseline.json:15` ("documented with an HTTP status that NO producer ... declares"); ADR-0114 line 37 records the six field-shaped top-level members as a known wart | | Spec contract on the field key | `packages/spec/src/data/field.zod.ts:1090-1094` (the `format` describe: "the write-time record validator's built-in email, url and phone checks key on `type`, never on this key") | ## Verification (final head `40758ef8`) - `node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands` derived **41** commands. I ran all 41 on `40758ef8`: 41 exited 0. - Reconciliation: `--ran` printed `41 derived famil(ies) accounted for — 41 run, 0 NOT-MEASURED (a DERIVED zero — all 41 recorded an exit code and none of them is 3)`. - On the first pass (`d56a2a7f`), four gates exited **3 (PREREQUISITE NOT MET)**: `check:doc-formula-expressions`, `check:doc-security-posture`, `check:skill-examples` and `check:docs-transcript-drift`. The lint, formula and client packages had not been built yet. After those builds all four re-ran with exit 0. - `pnpm --filter @objectstack/spec exec vitest run --maxWorkers=2 src/api/error-catalog-docs.test.ts` (the test that reads this page against the wire face): `Test Files 1 passed (1) · Tests 5 passed (5)` on `40758ef8`. - Not measured, and owned by CI: the families `dispatch-gates` lists outside its derived total, and the path-scheduled `Build Docs` / `Test Core` jobs. ## Changeset Docs-only. `content/docs/**` is not in any package's `files[]`, so this PR publishes nothing and falls under `skip-changeset`. Per the dispatch, this seat writes no labels. ## Acceptance notes - **Bounded in-place fix (the `VALIDATION_ERROR` example `invalid_format` → `invalid_email`).** All four exemption conditions hold: - same defect class (a docs line that says `format` where the real check keys on the email type); - a mechanical, pinned form (`zod-issues-to-fields.ts:83`); - the file is this card's claimed file; - the same gate family. It lies outside the claim's declared "(the `INVALID_FORMAT` entry)" sub-surface. The claim's file surface needs this entry added. - **`content/docs/ui/forms.mdx:229`** (`400 VALIDATION_FAILED` · "object schema validators fail (`required`, `format`, `length`, …)"): read, not edited. It lists kinds of constraint in the `When` column and gives no fix, so it does not tell anyone to edit a field `format` key. It does not carry the same false meaning. Not listed as a defect. - **Sibling entries on the same page (a finding, not fixed here):** `VALUE_TOO_LONG` and `VALUE_TOO_SHORT` also have no producer (`git grep` outside tests/`dist`: 0 hits each; control `'VALIDATION_FAILED'`: 70). Both appear in `scripts/error-status-unpinned-baseline.json`. The page still documents them as live causes. The record validator answers field-level `max_length` / `min_length` under `VALIDATION_FAILED` instead. This is reported to the seat for filing and is out of scope for this card. --- _Generated by [Claude Code](https://claude.ai/code/session_01VDtqoecgES7ScQYGbFVDRv)_ --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 276d96d commit 67ebc84

1 file changed

Lines changed: 16 additions & 3 deletions

File tree

‎content/docs/api/error-catalog.mdx‎

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ entry's cross-reference sentence so the in-process one stays findable.
6969
"httpStatus": 400,
7070
"retryable": false,
7171
"fields": [
72-
{ "field": "email", "message": "Invalid email format", "code": "invalid_format" }
72+
{ "field": "email", "message": "Invalid email format", "code": "invalid_email" }
7373
]
7474
}
7575
```
@@ -197,8 +197,21 @@ rather than deriving it from the table at the end of this page.
197197
</Callout>
198198

199199
### `INVALID_FORMAT`
200-
**Cause:** Field value does not match the expected format (e.g., invalid email, wrong date format).
201-
**Fix:** Ensure the value matches the field's `format` constraint or built-in type validation.
200+
**Cause:** Reserved for a value that does not match an expected format. **No route emits it
201+
today.** A malformed value is refused as a *field-level* failure inside `VALIDATION_FAILED`
202+
instead, and its `fields[].code` names what checked it:
203+
204+
- **the field's `type`** — an `email`, `url` or `phone` field runs a built-in shape check keyed
205+
on `type` itself and answers `invalid_email` / `invalid_url` / `invalid_phone`; a value a
206+
`date`, `datetime` or `time` field cannot parse answers `invalid_date` / `invalid_time`;
207+
- **a [`format` validation rule](/docs/data-modeling/validation#format-validation)** — its
208+
`regex`, or its named `format` (`email` | `url` | `phone` | `json`) — answers `invalid_format`.
209+
210+
A value that misses a declared `pattern` outside record metadata (a settings value, a request
211+
body a route parses with Zod) also answers field-level `invalid_format`.
212+
**Fix:** Do not branch on this code; branch on `VALIDATION_FAILED` + `fields[].code`. To change
213+
what a field accepts, change its `type` or the `format` validation rule — a field-level `format`
214+
key runs no write-time check on any field type, so editing it changes nothing.
202215
**Retry:** `no_retry`
203216

204217
### `VALUE_TOO_LONG`

0 commit comments

Comments
 (0)