Skip to content

fix(images): surface real upstream error instead of generic 502#3009

Open
liulinhuai wants to merge 1 commit into
Wei-Shaw:mainfrom
liulinhuai:fix/images-upstream-error-passthrough
Open

fix(images): surface real upstream error instead of generic 502#3009
liulinhuai wants to merge 1 commit into
Wei-Shaw:mainfrom
liulinhuai:fix/images-upstream-error-passthrough

Conversation

@liulinhuai
Copy link
Copy Markdown

Problem

Requests to /v1/images/generations and /v1/images/edits (e.g. gpt-image-2) return an opaque 502 "Upstream request failed" for many upstream errors, hiding the real status code and message. For example, a 400 invalid_request_error (unsupported parameter, moderation, invalid size, …) from the upstream reaches the client as a generic 502, making failures undebuggable.

Root cause

Both image forward paths routed every non-failover upstream error through the generic handleErrorResponse, whose final switch collapses anything that isn't 401/402/403/429 into a hardcoded 502 with the message "Upstream request failed" — discarding the upstream status code, type, code, message, and param.

The sibling Chat Completions and Messages compat paths already avoid this via handleCompatErrorResponse, which preserves the real upstream status and message. The images paths were the only ones still masking.

Fix

  • Add handleOpenAIImagesErrorResponse, modeled on handleCompatErrorResponse. It keeps all existing side-effects (ops logging, admin error-passthrough rules, ShouldHandleErrorCode, account-disable / secondary failover) but surfaces the real upstream status code + type/code/message/param, reusing the existing OpenAIImagesUpstreamError + writeOpenAIImagesUpstreamErrorResponse machinery. Returning OpenAIImagesUpstreamError also lets the images handler treat it as terminal (no fallback double-write).
  • Both forwardOpenAIImagesOAuth and forwardOpenAIImagesAPIKey now call it instead of handleErrorResponse for non-failover errors.
  • Added helpers openAIImagesUpstreamErrorFromHTTP and openAIImagesErrorTypeForStatus.

Failover behavior is unchanged — 5xx / 401 / 403 / 429 / 529 still trigger account failover exactly as before. This only affects errors the gateway had already decided not to retry, which is the class that was being masked.

Tests

Added TestOpenAIGatewayServiceForwardImages_OAuthUpstreamHTTPErrorSurfacesRealError, asserting an upstream 400 is passed through with the real status code, type, code, param, and message instead of a generic 502. Full internal/service and internal/handler packages pass.

🤖 Generated with Claude Code

The /v1/images/generations and /v1/images/edits paths routed every
non-failover upstream error through the generic handleErrorResponse,
whose final switch collapses anything that isn't 401/402/403/429 into a
hardcoded 502 "Upstream request failed" — discarding the actual upstream
status code, type, code, message, and param. So a gpt-image-2 400
(invalid_request_error, moderation, unsupported parameter, ...) reached
the client as an opaque 502.

The sibling Chat Completions and Messages compat paths already avoid this
via handleCompatErrorResponse, which preserves the real status and
message. Add the equivalent for images: handleOpenAIImagesErrorResponse
keeps all existing side-effects (ops logging, error-passthrough rules,
ShouldHandleErrorCode, account-disable/secondary-failover) but surfaces
the real upstream status + type/code/message/param by reusing the
existing OpenAIImagesUpstreamError machinery. Both forward paths now call
it instead of handleErrorResponse for non-failover errors.

Failover behavior (5xx / 401 / 403 / 429 / 529) is unchanged.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 3, 2026

All contributors have signed the CLA. ✅
Posted by the CLA Assistant Lite bot.

@liulinhuai
Copy link
Copy Markdown
Author

I have read the CLA Document and I hereby sign the CLA

@liulinhuai
Copy link
Copy Markdown
Author

recheck

github-actions Bot added a commit that referenced this pull request Jun 3, 2026
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