From 86cfdf5ffc258e9b1dd8ec0fadd6fe601d2916f1 Mon Sep 17 00:00:00 2001 From: Aaron Kanter Date: Wed, 29 Jul 2026 06:51:11 +0000 Subject: [PATCH 1/2] feat(errors): Error400.details.errors[] array for multi-field validation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace singular `details.field`/`details.constraint` with a typed `details.errors[]` array so submit endpoints (POST /customers, PATCH /customers/{id}) can report every invalid field in one round-trip. Adds `FieldError` schema — one entry per invalid field, carrying `field` (dot-notation path), optional `constraint` (FieldConstraint — the existing machine-readable validator hint), and optional `message` (human-readable explanation). Backwards-incompatible change to `Error400.details`: the singular `field` and `constraint` properties are removed. Approved per lightsparkdev/webdev#31110 review — no consumers of the previous shape had wired it into production yet. Consumers of this shape land in webdev#31110. --- mintlify/openapi.yaml | 29 ++++++++++++++----- openapi.yaml | 29 ++++++++++++++----- .../components/schemas/errors/Error400.yaml | 17 +++++------ .../components/schemas/errors/FieldError.yaml | 19 ++++++++++++ 4 files changed, 71 insertions(+), 23 deletions(-) create mode 100644 openapi/components/schemas/errors/FieldError.yaml diff --git a/mintlify/openapi.yaml b/mintlify/openapi.yaml index 0ae3a6da..ecfdd1a2 100644 --- a/mintlify/openapi.yaml +++ b/mintlify/openapi.yaml @@ -11303,6 +11303,22 @@ components: type: integer description: Maximum length in characters. example: 500 + FieldError: + type: object + required: + - field + description: One field-level validation failure. Field-validation errors on submit endpoints (e.g. `POST /customers`, `PATCH /customers/{id}`) emit an array of these under `details.errors` so platforms can render form-field-level UX for every failure in a single round-trip. + properties: + field: + type: string + description: Dot-notation path to the offending field. + example: taxIdentifier + constraint: + $ref: '#/components/schemas/FieldConstraint' + message: + type: string + description: Human-readable explanation of what's wrong with this field. + example: Value is not one of the allowed enum members. Error400: type: object required: @@ -11404,14 +11420,13 @@ components: description: Error message details: type: object - description: Additional error details. Shape varies by `code`. For field-validation errors on submit endpoints (e.g. `POST /customers`, `PATCH /customers/{id}`), `details.field` and `details.constraint` are populated so platforms can pre-validate their onboarding form before re-submitting. + description: Additional error details. Shape varies by `code`. For field-validation errors on submit endpoints (e.g. `POST /customers`, `PATCH /customers/{id}`), `details.errors[]` enumerates every invalid field so platforms can render form-field-level UX for the entire request in a single round-trip. properties: - field: - type: string - description: Dot-notation path to the offending field. Present on field-validation errors from submit endpoints. - example: taxIdentifier - constraint: - $ref: '#/components/schemas/FieldConstraint' + errors: + type: array + description: One entry per invalid field. Present on field-validation errors from submit endpoints. + items: + $ref: '#/components/schemas/FieldError' additionalProperties: true Error501: type: object diff --git a/openapi.yaml b/openapi.yaml index 0ae3a6da..ecfdd1a2 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -11303,6 +11303,22 @@ components: type: integer description: Maximum length in characters. example: 500 + FieldError: + type: object + required: + - field + description: One field-level validation failure. Field-validation errors on submit endpoints (e.g. `POST /customers`, `PATCH /customers/{id}`) emit an array of these under `details.errors` so platforms can render form-field-level UX for every failure in a single round-trip. + properties: + field: + type: string + description: Dot-notation path to the offending field. + example: taxIdentifier + constraint: + $ref: '#/components/schemas/FieldConstraint' + message: + type: string + description: Human-readable explanation of what's wrong with this field. + example: Value is not one of the allowed enum members. Error400: type: object required: @@ -11404,14 +11420,13 @@ components: description: Error message details: type: object - description: Additional error details. Shape varies by `code`. For field-validation errors on submit endpoints (e.g. `POST /customers`, `PATCH /customers/{id}`), `details.field` and `details.constraint` are populated so platforms can pre-validate their onboarding form before re-submitting. + description: Additional error details. Shape varies by `code`. For field-validation errors on submit endpoints (e.g. `POST /customers`, `PATCH /customers/{id}`), `details.errors[]` enumerates every invalid field so platforms can render form-field-level UX for the entire request in a single round-trip. properties: - field: - type: string - description: Dot-notation path to the offending field. Present on field-validation errors from submit endpoints. - example: taxIdentifier - constraint: - $ref: '#/components/schemas/FieldConstraint' + errors: + type: array + description: One entry per invalid field. Present on field-validation errors from submit endpoints. + items: + $ref: '#/components/schemas/FieldError' additionalProperties: true Error501: type: object diff --git a/openapi/components/schemas/errors/Error400.yaml b/openapi/components/schemas/errors/Error400.yaml index 24801121..97bcaad5 100644 --- a/openapi/components/schemas/errors/Error400.yaml +++ b/openapi/components/schemas/errors/Error400.yaml @@ -101,15 +101,14 @@ properties: description: >- Additional error details. Shape varies by `code`. For field-validation errors on submit endpoints (e.g. `POST /customers`, `PATCH /customers/{id}`), - `details.field` and `details.constraint` are populated so platforms can - pre-validate their onboarding form before re-submitting. + `details.errors[]` enumerates every invalid field so platforms can render + form-field-level UX for the entire request in a single round-trip. properties: - field: - type: string + errors: + type: array description: >- - Dot-notation path to the offending field. Present on field-validation - errors from submit endpoints. - example: taxIdentifier - constraint: - $ref: ./FieldConstraint.yaml + One entry per invalid field. Present on field-validation errors from + submit endpoints. + items: + $ref: ./FieldError.yaml additionalProperties: true diff --git a/openapi/components/schemas/errors/FieldError.yaml b/openapi/components/schemas/errors/FieldError.yaml new file mode 100644 index 00000000..5b74061c --- /dev/null +++ b/openapi/components/schemas/errors/FieldError.yaml @@ -0,0 +1,19 @@ +type: object +required: + - field +description: >- + One field-level validation failure. Field-validation errors on submit + endpoints (e.g. `POST /customers`, `PATCH /customers/{id}`) emit an array of + these under `details.errors` so platforms can render form-field-level UX + for every failure in a single round-trip. +properties: + field: + type: string + description: Dot-notation path to the offending field. + example: taxIdentifier + constraint: + $ref: ./FieldConstraint.yaml + message: + type: string + description: Human-readable explanation of what's wrong with this field. + example: Value is not one of the allowed enum members. From 06d7b8cbb31eb940f05728eedf567c16d8b57306 Mon Sep 17 00:00:00 2001 From: Aaron Kanter Date: Wed, 29 Jul 2026 07:23:34 +0000 Subject: [PATCH 2/2] test(cli): update Error400.details fixture to new errors[] shape Greptile flagged the fixture as stale: it constructed and asserted on `details: { field: 'email' }` (the singular shape this PR removed). Updated to `details: { errors: [{ field: 'email' }] }` so the test exercises the new FieldError-array contract. Behavior under test is unchanged (the CLI passes details through verbatim); this just realigns the fixture with the current spec. --- cli/test/client.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cli/test/client.test.ts b/cli/test/client.test.ts index d649ff4c..e7218941 100644 --- a/cli/test/client.test.ts +++ b/cli/test/client.test.ts @@ -9,14 +9,14 @@ describe("error handling", () => { status: 400, code: "INVALID_REQUEST", message: "Bad request", - details: { field: "email" }, + details: { errors: [{ field: "email" }] }, }, }); const parsed = JSON.parse(stdout); expect(parsed.success).toBe(false); expect(parsed.error.code).toBe("INVALID_REQUEST"); - expect(parsed.error.details).toEqual({ field: "email" }); + expect(parsed.error.details).toEqual({ errors: [{ field: "email" }] }); // The whole error envelope must not be nested under details. expect(parsed.error.details.code).toBeUndefined(); });