Skip to content

fix(translate): preserve upstream error details - #712

Merged
Menci merged 20 commits into
mainfrom
fix/translate-error-fields
Nov 12, 2026
Merged

Menci merged 20 commits into
mainfrom
fix/translate-error-fields

Conversation

@Menci

@Menci Menci commented Nov 11, 2026 •

Copy link
Copy Markdown
Owner

Restate recognized structured upstream errors into the client's protocol before and during streams. Preserve nullable named fields, unconsumed aliases, envelope metadata and protocol-specific diagnostics while retaining semantic response headers. Unexpected parser failures preserve their error chain, and unrecognized bodies pass through.

Preserve distinct colliding metadata values under the first unused _1, _2, ... suffix. Existing container/inner-error values retain their original key; equal values at the same original key coalesce. Reserve every explicitly stated key before allocating suffixes, and merge namespaces once so source projection cannot duplicate metadata.

Carry Responses continuation failures through the normal event lifecycle. A structured non-streaming error body becomes the corresponding error event, followed by the aggregate response.failed resource. Streaming clients receive both events; non-streaming collection drains the failed resource and renders the original standard error fields as JSON. The original HTTP status and headers are not retained across this event boundary; the downstream HTTP status is reconstructed from the standard error code or classification type, with 502 reserved for unknown classifications. Accumulated output usage is still recorded once.

Protocol errors are JSON; this change adds no plaintext interpretation or status-derived fallback error code. Gemini HTTP 502 errors use the shared protocol mapping and therefore report RPC status UNAVAILABLE.

Depends on #709's prepared-trip contract and local gateway error handling. Focused validation covers flat and nested Responses errors, nullable codes, HTTP classification, extension fields, raw numeric tokens, error-to-failed lifecycle consumers, accumulated usage telemetry, Gemini status mapping, metadata collisions and explicit suffix names. The latest local verification passed 442 named gateway/protocol tests, both owning TypeScript projects and exact changed-file lint.

Menci added 10 commits November 12, 2026 04:40
Replace fluent protocol subpaths with named root translators returning plain trips or input failures. Keep request builders and event adapters intact while containing expected input exceptions at public operations.

Consume translation failures at gateway attempt and payload boundaries, and encode rewritten JSON errors at the transport boundary. Preserve the current model context and remote-image loader requirements for the pairwise request backend.

Validate named translation and gateway suites, owning TypeScript projects, and changed lint targets.
Restate recognized upstream errors through source-owned converters before and during streams. Preserve independent error classifications, nullable code and param values, envelope metadata, and one merged provider extension container.

Use the same recognized context-overflow decision for Gemini HTTP and body codes. Keep unknown response bytes untouched and propagate unexpected parser failures with their original error and cause.

Validate 322 tests in 19 named files, changed-file ESLint, and the translate and gateway TypeScript projects.
Normalize HTTP and streaming error envelopes through the same metadata merge. Preserve outer request identifiers and trace fields in the existing extension container while retaining error-level collision priority.

Distinguish event transport fields from native error payloads so canonical payloads retain their original reference and classification when no envelope data remains.

Validate 324 tests in 19 named files, ESLint on all four changed files, and the translate and gateway TypeScript projects.
Move each source protocol's error converters into as-source/error.ts so HTTP error restatement and SSE output share the focused error owner. Preserve the extracted implementation byte for byte.

Align six existing error expectations in three test files with retained upstream details and independent classifications.

Validate 376 tests in 22 named files, all 17 changed TypeScript lint targets, and the translate and gateway TypeScript projects.
Preserve the param and code supplied by raw translation input failures in Messages and GenerateContent error envelopes. Omit absent details and keep the rejecting candidate performance context intact.

Keep protocol error results precise and validate both detail envelopes, the named translation boundary suites, and gateway TypeScript checks.
Port the reviewed capture, error telemetry, and Responses attempt explanations to their public-boundary owners. Remove redundant dispatcher and assertion narration and update the dashboard capture reference.
Move reviewed error-format explanations to dedicated protocol error owners and HTTP wrappers. Clarify diagnostic field projection, unknown-body passthrough, and replacement headers while preserving the existing status policy and envelope metadata behavior.
Keep the reviewed Struct Any explanation beside the public-boundary field-preservation matrix.
Move Responses canonicalization and Gemini Part classification into their protocol modules. Protocol errors are ordinary native data, adapted at translation entrypoints. Share HTTP/RPC status facts while preserving gateway status policy.
Share the native HTTP/RPC mapping while retaining this boundary's UNKNOWN classification for 502 and unrecognized codes.
Keep expected token-counting input failures as gateway API errors so final response rendering records the selected candidate's zero-output error. Preserve fallback across candidates and verify final failure attribution and successful fallback through real HTTP requests and performance records.
Preserve every distinct same-named upstream error value beneath the first available numeric suffix while reserving original keys. Keep container and inner-error precedence, and coalesce equal JSON structures without rewriting raw number tokens.

Merge HTTP and SSE namespaces before projection, keeping loose fields and canonical values from being duplicated during source rendering.

Verified 91 scoped tests, the translate TypeScript project, and ESLint for all changed files.
Remove the translated-error exception that turned HTTP 502 into UNKNOWN. Reuse the protocol mapping to UNAVAILABLE while preserving HTTP 502, the unknown-status fallback and context-overflow classification.
Carry standard Responses error bodies through the hosted-tool event lifecycle, drain the following response.failed resource, and reconstruct non-streaming errors without retaining an HTTP-result side channel. Preserve accumulated usage telemetry while allowing stateful, affinity, HTTP, and WebSocket consumers to observe the complete failure lifecycle.
Choose the non-streaming HTTP status from the standard Responses error code or type after the internal error-to-failed lifecycle completes. Preserve 502 only for unknown classifications and keep the reconstructed JSON body unchanged.
@Menci
Menci changed the base branch from refactor/translate-public-boundary to main November 12, 2026 14:07
…ields

# Conflicts:
#	packages/protocols/src/openai-responses/index.ts
#	packages/translate/AGENTS.md
#	packages/translate/__tests__/protocols/anthropic-messages/as-source/context-window-error_test.ts
#	packages/translate/__tests__/protocols/chat-legacy-round-trip_test.ts
#	packages/translate/__tests__/protocols/chat-reasoning-round-trip_test.ts
#	packages/translate/__tests__/protocols/openai-chat-completions/as-source/continuous-usage_test.ts
#	packages/translate/__tests__/protocols/round-trip-receive_test.ts
#	packages/translate/__tests__/protocols/routes_test.ts
#	packages/translate/src/index.ts
#	packages/translate/src/ir/output/types.ts
#	packages/translate/src/protocols/anthropic-messages/as-source/context-window-error.ts
#	packages/translate/src/protocols/anthropic-messages/as-source/events.ts
#	packages/translate/src/protocols/anthropic-messages/via-openai-chat-completions/request.ts
#	packages/translate/src/protocols/anthropic-messages/via-openai-chat-completions/translate.ts
#	packages/translate/src/protocols/anthropic-messages/via-openai-responses/request.ts
#	packages/translate/src/protocols/anthropic-messages/via-openai-responses/translate.ts
#	packages/translate/src/protocols/gemini-generate-content/as-source/events.ts
#	packages/translate/src/protocols/gemini-generate-content/via-anthropic-messages/request.ts
#	packages/translate/src/protocols/gemini-generate-content/via-anthropic-messages/translate.ts
#	packages/translate/src/protocols/gemini-generate-content/via-openai-chat-completions/request.ts
#	packages/translate/src/protocols/gemini-generate-content/via-openai-chat-completions/translate.ts
#	packages/translate/src/protocols/gemini-generate-content/via-openai-responses/request.ts
#	packages/translate/src/protocols/gemini-generate-content/via-openai-responses/translate.ts
#	packages/translate/src/protocols/openai-chat-completions/as-source/events.ts
#	packages/translate/src/protocols/openai-chat-completions/via-anthropic-messages/request.ts
#	packages/translate/src/protocols/openai-chat-completions/via-anthropic-messages/translate.ts
#	packages/translate/src/protocols/openai-chat-completions/via-openai-responses/content.ts
#	packages/translate/src/protocols/openai-chat-completions/via-openai-responses/request.ts
#	packages/translate/src/protocols/openai-chat-completions/via-openai-responses/translate.ts
#	packages/translate/src/protocols/openai-responses/as-target/events.ts
#	packages/translate/src/protocols/openai-responses/via-anthropic-messages/request.ts
#	packages/translate/src/protocols/openai-responses/via-anthropic-messages/translate.ts
#	packages/translate/src/protocols/openai-responses/via-openai-chat-completions/content.ts
#	packages/translate/src/protocols/openai-responses/via-openai-chat-completions/request.ts
#	packages/translate/src/protocols/openai-responses/via-openai-chat-completions/translate.ts
@Menci
Menci marked this pull request as ready for review November 12, 2026 14:17
@Menci
Menci merged commit 8c9e722 into main Nov 12, 2026
21 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant