docs(api): publish details.issues and open meta on the error envelope

Every documented 422, 401, 403, 409, 410 and 429 points at one
`ErrorEnvelope`, and that schema declared `data`, `error` and a `meta`
closed to `requestId` + `errorCode`. Two things were wrong with it.

`returnAllZodIssues` has sent a third top-level key since v1.4.42 —
`details.issues`, one entry per rejected field — from 166 route files.
It exists so a client can fix three bad fields in one round-trip instead
of three, and the doc comment says so, yet no component schema anywhere
declared it. A client generated from the contract had no field to read
it from, so the feature was invisible to exactly the consumer it was
built for. It is now a schema, with the `unrecognized_keys` list and the
promise that no rejected value is echoed back.

And `meta` was closed while real refusals put more in it: `removedIn` /
`replacedBy` on a 410, `module` beside `module.disabled`, the
per-integration context on a failed connection test. Closed plus those
keys means the response was invalid against its own published schema and
a strict decoder is entitled to reject it. It is open now.

No wire change; both halves describe what the server already sends.
This commit is contained in:
Marc-André Bombeck committed 2026-09-10 04:03:02 +02:00
1 parent 1d2744a109
commit fd8fc0ec0e
2 files changed
+105 -5

No files matched your search

+46 -2
View File
@@ -29018,19 +29018,63 @@ components:
type: "null"
error:
type: string
details:
description: "Present on a 422 raised by the multi-issue validator: every field the request got wrong, not only the
first. Absent on every other status."
type: object
properties:
issues:
type: array
items:
$ref: "#/components/schemas/ValidationIssue"
required:
- issues
additionalProperties: false
meta:
type: object
properties:
requestId:
type: string
errorCode:
description: Stable machine code for this refusal. Branch on it rather than on `error`, which is prose and may be
reworded.
type: string
additionalProperties: false
additionalProperties: {}
required:
- data
- error
additionalProperties: false
description: "Standard error response: data is null, error is human prose."
description: "Standard error response: `data` is null, `error` is human prose. `meta.errorCode` carries the stable
machine code where one exists, and `meta` may carry further per-refusal context. A 422 from the multi-issue
validator additionally carries `details.issues` — every field the request got wrong, so a client can fix them in
one round-trip."
ValidationIssue:
type: object
properties:
path:
type: string
description: Dot-joined path to the rejected field, e.g. `entries.3.measuredAt`. Empty string when the whole body was
rejected.
code:
type: string
description: Zod issue code, e.g. `invalid_type`, `too_small`, `unrecognized_keys`. Treat an unfamiliar code as a
generic rejection of `path`.
message:
type: string
description: English sentence describing the rejection. Safe to log; show the user your own wording keyed on `path`.
keys:
description: "Only on `unrecognized_keys`: the refused key names, bounded to 10 and 64 characters each. Zod reports
every unknown key of one object in a single issue whose `path` is the object, so the names live here and
nowhere in `path`."
type: array
items:
type: string
required:
- path
- code
- message
additionalProperties: false
description: "One rejected field in a multi-issue 422. Sanitised: no rejected VALUE is echoed back."
CycleCustomSymptomCreatedEnvelope:
type: object
properties: