← Back to PRs

#17888: fix: normalize /v1/responses input for clients that omit type field

by lazmo88 open 2026-02-16 08:34 View on GitHub →
gateway size: XS
## Summary Fixes `400 Bad Request` ("input: Invalid input") when OpenAI SDK clients send `/v1/responses` input messages without the `type: "message"` discriminator field. - n8n (v2.2.4+), and potentially other clients, send `{"role":"user","content":"hello"}` without `type` — OpenAI's API accepts this, but the Zod `discriminatedUnion("type", [...])` schema rejects it - Adds a `normalizeResponseInput()` pre-processing step before Zod validation - Also normalizes `type: "text"` content parts to `type: "input_text"` for clients that use the Chat Completions content format - Changes `CreateResponseBodySchema` from `.strict()` to `.strip()` so unknown top-level fields (e.g. `parallel_tool_calls`, `background`) forwarded by clients are silently discarded instead of causing validation errors ## Changes **`src/gateway/openresponses-http.ts`:** - Adds `normalizeResponseInput()` function (~25 lines) - Wraps the existing `CreateResponseBodySchema.safeParse()` call with normalization **`src/gateway/open-responses.schema.ts`:** - Changes `.strict()` to `.strip()` on `CreateResponseBodySchema` ## Normalization rules | Client sends | Normalized to | Why | |---|---|---| | `{"role":"user","content":"..."}` (no `type`) | `{"type":"message","role":"user","content":"..."}` | OpenAI infers `type: "message"` when `role` is present | | `{"type":"text","text":"..."}` in content array | `{"type":"input_text","text":"..."}` | Some clients use Chat Completions content format | ## Test Plan - [x] `POST /v1/responses` with `[{"role":"user","content":"hello"}]` (no type) — was 400, now accepted - [x] `POST /v1/responses` with `[{"type":"message","role":"user","content":[{"type":"text","text":"hello"}]}]` — was 400, now accepted - [x] `POST /v1/responses` with correct format still works - [x] `POST /v1/responses` with string input still works - [x] Tested with n8n v2.2.4 OpenAI Chat Model node (Responses API mode) - [x] `pnpm build` passes with zero errors - [x] Rebased onto current main ## AI Disclosure 🤖 - **AI-assisted**: Yes — written with Claude (Opus), with human review and testing - **Testing level**: Build-verified (`pnpm build` zero errors); endpoint tested with n8n v2.2.4 OpenAI Chat Model node - **Understanding**: The author understands the code — it pre-processes the raw request body to infer `type: "message"` for items that have `role` but no `type`, matching OpenAI's own inference behavior, and rewrites `type: "text"` content parts to the `input_text` variant expected by the Zod schema

Most Similar PRs