You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
* feat(spec)!: EnhancedApiError.fieldErrors -> fields, tombstoned (ADR-0114 D4, #3977)
Completes the one thing #4035 decided but did not execute. The wire has always
carried `fields`; `fieldErrors` was declared and emitted by nobody, so a reader
keying on it was reading a field no server sent — ADR-0078's silently-inert
declaration, on the error envelope.
Tombstoned rather than deleted, because the schema is not .strict(): a plain
removal would let a producer still writing the old name parse clean and lose the
per-field detail, answering a validation failure that mentions no field.
retiredKey() turns that into a rejection carrying the rename.
Registered as a SEMANTIC chain entry, not a conversion, and the distinction is the
point. A conversion rewrites author metadata; this is a response envelope, and no
stack, example or template carries the key (checked across packages/, examples/,
templates/, apps/). A no-op conversion with an identity fixture would claim a
rewrite that does not exist. The analytics-query-request-* entries set the
precedent one step earlier in the same major: an HTTP-only surface with nothing
stored to rewrite is a semantic entry with a reason and an acceptance criterion —
which is what actually reaches spec-changes.json, the upgrade guide and the
spec_changes MCP tool.
Docs followed, and two examples were teaching the opposite of this ADR: the
server guide hand-rolled a Zod mapping with code: 'invalid_field' — a top-level
code in a field position — and the client guide's error class carried the dead
name. The server example now calls zodIssuesToFields, which is the mapping the
platform's own routes use.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MaSQn77TT5fUgHK9CesaDK
* docs(releases): v17 breaking-changes gets the error-code vocabulary entries it was missing
The v17 page documents each breaking change under its own heading, and the whole
ADR-0112 line had none — the largest wire-visible change in it appeared only as a
passing mention 600 lines down. That is the worst gap to leave, because a missed
error-code branch fails SILENTLY: nothing throws, the affordance it guarded just
disappears. Eleven console branches broke that way without one test failing.
Two entries: ADR-0112's vocabulary unification (with the generic-condition
collapse table, the four routes that stopped putting a code in the message slot,
and the case-insensitive advice for consumers spanning the upgrade), and
ADR-0114's field-level catalog plus this PR's fieldErrors -> fields rename.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MaSQn77TT5fUgHK9CesaDK
---------
Co-authored-by: Claude <noreply@anthropic.com>
Copy file name to clipboardExpand all lines: content/docs/api/error-handling-server.mdx
+17-12Lines changed: 17 additions & 12 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -8,7 +8,7 @@ description: Best practices for handling and throwing errors in ObjectStack plug
8
8
This guide covers best practices for handling and throwing errors within ObjectStack plugins and server-side code — from creating custom errors with proper codes to transaction rollback and integration with `safeParsePretty()`.
9
9
10
10
<Callouttype="info">
11
-
**Error Contract:** ObjectStack defines a standardized error envelope, `ErrorResponseSchema` (exported from `@objectstack/spec/api`). It wraps an `EnhancedApiError` with a machine-readable `code`, `httpStatus`, optional `category`, and `fieldErrors`. This is the spec's target contract for plugin/hook authors to throw against — but the kernel REST server (`@objectstack/rest`) that serves `/api/v1/data/*` does not auto-translate an arbitrary thrown error into this envelope today. It emits a flatter `{ error, code }` shape and only recognizes a small, fixed set of SCREAMING_SNAKE_CASE codes (`VALIDATION_FAILED`, `PERMISSION_DENIED`, `RECORD_NOT_FOUND`, `CONCURRENT_UPDATE`, `DELETE_RESTRICTED`, …). See the [API Overview](/docs/api#error-handling) and [Wire Format](/docs/api/wire-format#7-error-response-format) for both wire formats in use, and the [Error Catalog](/docs/api/error-catalog) for the full `StandardErrorCode` list.
11
+
**Error Contract:** ObjectStack defines a standardized error envelope, `ErrorResponseSchema` (exported from `@objectstack/spec/api`). It wraps an `EnhancedApiError` with a machine-readable `code`, `httpStatus`, optional `category`, and `fields` (one entry per offending value). This is the spec's target contract for plugin/hook authors to throw against — but the kernel REST server (`@objectstack/rest`) that serves `/api/v1/data/*` does not auto-translate an arbitrary thrown error into this envelope today. It emits a flatter `{ error, code }` shape and only recognizes a small, fixed set of SCREAMING_SNAKE_CASE codes (`VALIDATION_FAILED`, `PERMISSION_DENIED`, `RECORD_NOT_FOUND`, `CONCURRENT_UPDATE`, `DELETE_RESTRICTED`, …). See the [API Overview](/docs/api#error-handling) and [Wire Format](/docs/api/wire-format#7-error-response-format) for both wire formats in use, and the [Error Catalog](/docs/api/error-catalog) for the full `StandardErrorCode` list.
12
12
</Callout>
13
13
14
14
---
@@ -18,7 +18,7 @@ This guide covers best practices for handling and throwing errors within ObjectS
18
18
ObjectStack does not ship a base error class — there is no `ObjectStackError`
19
19
export. Instead, define a small server-side helper that extends the native
20
20
`Error` and carries the fields from the `EnhancedApiError` schema (`code`,
21
-
`httpStatus`, `fieldErrors`; `category` is optional). The valid `code` values are
21
+
`httpStatus`, `fields`; `category` is optional). The valid `code` values are
22
22
SCREAMING_SNAKE (ADR-0112): a `StandardErrorCode` member (e.g. `VALIDATION_ERROR`,
23
23
`RESOURCE_CONFLICT`, `PERMISSION_DENIED`) or a code your package registered in
24
24
`ERROR_CODE_LEDGER` (see `@objectstack/spec/api`).
@@ -27,15 +27,15 @@ SCREAMING_SNAKE (ADR-0112): a `StandardErrorCode` member (e.g. `VALIDATION_ERROR
|**fieldErrors**|`any`| optional |[REMOVED]`EnhancedApiError.fieldErrors` was renamed to `fields` in @objectstack/spec 17 (ADR-0114 D4, #3977) — the array is unchanged, only the property name. Every producer already emitted `fields`; `fieldErrors` was declared and never emitted, so a reader keying on it was reading a field no server sent. |
57
58
|**timestamp**|`string`| optional | When the error occurred |
58
59
|**requestId**|`string`| optional | Request ID for tracking |
59
60
|**traceId**|`string`| optional | Distributed trace ID |
0 commit comments