Skip to content

Check the HTTP status code for JSON responses #469

Closed

Description

@nezhyborets

JSON requests never check the HTTP status code. They seem to handle API errors only because JSONResponseDecoder falls back to decoding an API error when the expected result type fails to decode (Sources/OpenAI/Private/JSONResponseDecoder.swift). That fallback misses two cases:

  • The error body isn't an API error, such as an HTML page from a proxy or gateway. The caller gets a DecodingError about the expected type instead of an error carrying the status code.
  • The error body decodes as the expected type. With .relaxed parsing, which fills in missing required fields, an error body could decode into a result with default values and be returned as a success.

#401 adds a status check for responses read as raw data (files.content(id:) and audioCreateSpeech), in URLResponseHandler.throwIfErrorStatus. It throws the decoded APIErrorResponse for a status of 400 or above, falling back to OpenAIError.statusError, as StreamingSession already does. JSON responses were left out because changing them affects every endpoint.

Proposal

  • Route all four URLResponseHandler methods (JSON and raw, with and without an error: parameter) through one function, probably unwrap with the response added, that throws a transport error first and then checks the status. That way completion-handler, async and Combine requests behave the same.
  • Check that providers supported through .relaxed parsing still work, in particular whether any of them return successful responses with a status of 400 or above, or error bodies in a shape JSONResponseErrorDecoder doesn't know.
  • Add tests with a non-2xx status and an error body, and with a non-API body, for all three flavours.

This changes what JSON requests throw in some error cases (OpenAIError.statusError instead of a DecodingError), so it needs a CHANGELOG entry.

Activity

  1. mvanhorn commented on Oct 14, 2026

    @mvanhorn
    Contributor

    The JSON overloads of URLResponseHandler ran response middleware and then decodeJson, and never called throwIfErrorStatus. That status check existed only on the raw-data overloads.

    All four URLResponseHandler entry points, JSON and raw, with and without an error argument, now take the body from interceptedData.

    #471

  2. added a commit that references this issue on Nov 6, 2026
    a632931
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions