Skip to content

Commit 836aad2

Browse files
docs(error-catalog): VALUE_TOO_LONG / VALUE_TOO_SHORT name the field-level codes that really arrive (#20004)
Fixes #19879 Clause-②: no ## What `content/docs/api/error-catalog.mdx`, the `VALUE_TOO_LONG` and `VALUE_TOO_SHORT` entries only. Both entries gave a live cause and a fix, as if a client could branch on the code. No producer emits either code. Both entries now say so, following the shape the `INVALID_FORMAT` entry got in #19878: the code is reserved, no route emits it today, and a length miss arrives as a field-level `max_length` / `min_length` entry. Each entry now says where that entry rides on each path: `400 VALIDATION_FAILED` with `fields[]` for record writes and Zod-parsed request bodies (top-level on `/data`, under `details` through the runtime dispatcher), and `400 SETTINGS_VALIDATION` with `details.fields[]` for a settings write. The fix line names both envelopes. Both entries stay because the enum still declares the codes. ## Evidence (measured on `origin/main` `e8f163fc`) - **No producer.** `git grep -nE 'VALUE_TOO_(LONG|SHORT)'` outside tests hits only the enum members `packages/spec/src/api/errors.zod.ts:58-59`, the baseline rows `scripts/error-status-unpinned-baseline.json:27-28`, this page, the generated `content/docs/references/**` pages, and ADR-0114, which records these members as a known wart. A grep for other spellings (`VALUE_TOO`, `TOO_LONG`, `TOO_SHORT`) finds only the unrelated `PASSWORD_TOO_SHORT` in a plugin-auth test. Positive control: `INVALID_FORMAT` hits `errors.zod.ts:57`. - **Record writes.** `packages/objectql/src/validation/record-validator.ts:695-699` sends `fail('max_length', { maxLength, actual })` and `fail('min_length', { minLength, actual })` for `BOUNDED_STRING_FIELD_TYPES`. `buildFieldError` puts that object on the wire as `fields[].constraint`, and the envelope's top-level code is `VALIDATION_FAILED` (`VALIDATION_FAILED_CODE`, `:195`). - **Zod-parsed request bodies.** `packages/spec/src/api/zod-issues-to-fields.ts:74-81` maps `too_small` / `too_big` to `min_length` / `max_length` when the value is not a number, bigint, date, array or set. Numbers and dates map to `min_value` / `max_value`, and arrays and sets to `min_items` / `max_items`. That is why the page says "a string". The REST routes that use this send `code: 'VALIDATION_FAILED'` (for example `packages/rest/src/rest-server.ts:8960-8963`). - **Settings writes (a different envelope).** `packages/services/service-settings/src/settings-service.ts:397-400` returns `max_length` / `min_length` with `constraint { minLength?, maxLength?, actual }` for a settings value outside its declared length window. `:2145` pushes it into the errors list, and `:2167` throws `SettingsValidationError` (`settings-service.types.ts:583-584`, `code = 'SETTINGS_VALIDATION'`). `packages/services/service-settings/src/settings-routes.ts:215-217` serves it as `sendError(res, 400, 'SETTINGS_VALIDATION', …, { details: { namespace, fields } })`, and `packages/types/src/response-envelope.ts` `sendError` writes that as `{ success: false, error: { code, message, details } }`. So a settings length miss is top-level `SETTINGS_VALIDATION` with the entry in `error.details.fields[]`, not `VALIDATION_FAILED`. - **Where `VALIDATION_FAILED` puts the list.** On the `/data` routes it is flat (`packages/rest/src/error-response.ts:1152-1160`, `mapDataError`: top-level `fields`). Through the runtime dispatcher it is nested (`packages/runtime/src/dispatcher-plugin.ts:645`, `validationFailureDetails`: `details.fields`). The page's own `VALIDATION_FAILED` callout already documents both, so the entries link to it rather than restating it. - The field-level spellings are the same on all three paths: `max_length` / `min_length`. The envelope differs: `VALIDATION_FAILED` for records and Zod bodies, `SETTINGS_VALIDATION` for settings. ## Not touched - The wire-count sentence at `:6`, the `CONCURRENT_LIMIT_EXCEEDED` entry and `scripts/error-status-unpinned-baseline.json` are not changed. Open PR #19957 edits them. - `VALUE_OUT_OF_RANGE` and `MISSING_REQUIRED_FIELD` are not changed. Both have producers. - The page's frontmatter and headings are not changed. ## Changeset None. This is a docs-only change under `content/docs/`, and no published package's `files[]` changes, so it falls under `skip-changeset`. The PM seat applies the label. ## Gates Derived with `node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands` from the merge-base change set (1 path). All 41 derived commands ran on HEAD `37431df1` and exited 0. The derivation is unchanged from the first head, `ab8b19ea`. They include `pnpm check:doc-authoring`, `pnpm check:doc-anchors`, `pnpm check:nul-bytes`, `pnpm check:error-status-conformance`, `pnpm check:docs-spec-enumerations` and `pnpm --filter @objectstack/spec run check:docs`. The prerequisite closures (`lint` / `formula` / `client-react`, which pulls in `spec`) were built under the verify lock first. Reconciliation with `--ran` and the recorded exit codes: `41 derived, 41 run, 0 NOT-MEASURED, 0 UNRUN` (a derived zero). No package source changed, so no package tests or typecheck are owed. ## Rework (PM review) The first head said every length miss arrives in `VALIDATION_FAILED`, which is wrong for settings writes. The second commit, `37431df1`, names `SETTINGS_VALIDATION` + `details.fields[]` for that path in both the Cause and the Fix lines. The `#validation_failed` link resolves: `check:doc-anchors` passes, with 377 fragment links resolved. ## Acceptance notes - The page's intro counts "52 error codes reachable on the wire", but the page carries 53 code headings, and several of them are reserved codes with no emitter (`INVALID_FORMAT`, `INVALID_REFERENCE`, and now these two). Whether that count should include reserved codes is a question for the line PR #19957 already edits. It is not changed here. --- _Generated by [Claude Code](https://claude.ai/code/session_01VDtqoecgES7ScQYGbFVDRv)_ --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 455dcc0 commit 836aad2

1 file changed

Lines changed: 30 additions & 4 deletions

File tree

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

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -215,13 +215,39 @@ key runs no write-time check on any field type, so editing it changes nothing.
215215
**Retry:** `no_retry`
216216

217217
### `VALUE_TOO_LONG`
218-
**Cause:** String value exceeds the field's `maxLength` constraint.
219-
**Fix:** Truncate the value to the maximum allowed length.
218+
**Cause:** Reserved for a string value longer than its declared maximum. **No route emits it
219+
today.** A length miss is refused as a *field-level* `max_length` entry instead, and where that
220+
entry rides depends on what was written:
221+
222+
- **a record write** (a string over a field's `maxLength`) and **a request body a route parses
223+
with Zod** answer `400 VALIDATION_FAILED` with the entry in `fields[]` — top-level on the
224+
`/data` routes, under `details` when the runtime dispatcher serves it (see
225+
[`VALIDATION_FAILED`](#validation_failed)); on a record write its `constraint` carries
226+
`maxLength` and the `actual` length;
227+
- **a settings write** (a value over its declared maximum) answers `400 SETTINGS_VALIDATION`
228+
with the entry in `details.fields[]`.
229+
230+
**Fix:** Do not branch on this code; branch on `VALIDATION_FAILED` + `fields[].code`
231+
`max_length`, or on `SETTINGS_VALIDATION` + `details.fields[].code` `max_length` for a settings write,
232+
and shorten the value to fit the declared maximum.
220233
**Retry:** `no_retry`
221234

222235
### `VALUE_TOO_SHORT`
223-
**Cause:** String value is below the field's `minLength` constraint.
224-
**Fix:** Provide a longer value that meets the minimum length requirement.
236+
**Cause:** Reserved for a string value shorter than its declared minimum. **No route emits it
237+
today.** A length miss is refused as a *field-level* `min_length` entry instead, and where that
238+
entry rides depends on what was written:
239+
240+
- **a record write** (a string under a field's `minLength`) and **a request body a route parses
241+
with Zod** answer `400 VALIDATION_FAILED` with the entry in `fields[]` — top-level on the
242+
`/data` routes, under `details` when the runtime dispatcher serves it (see
243+
[`VALIDATION_FAILED`](#validation_failed)); on a record write its `constraint` carries
244+
`minLength` and the `actual` length;
245+
- **a settings write** (a value under its declared minimum) answers `400 SETTINGS_VALIDATION`
246+
with the entry in `details.fields[]`.
247+
248+
**Fix:** Do not branch on this code; branch on `VALIDATION_FAILED` + `fields[].code`
249+
`min_length`, or on `SETTINGS_VALIDATION` + `details.fields[].code` `min_length` for a settings write,
250+
and lengthen the value to meet the declared minimum.
225251
**Retry:** `no_retry`
226252

227253
### `VALUE_OUT_OF_RANGE`

0 commit comments

Comments
 (0)