Skip to content

fix: surface backend error messages in Java and Go Interactions SDK errors - #189

Open
copybara-service[bot] wants to merge 1 commit into
mainfrom
copybara/1015698193
Open

copybara-service[bot] wants to merge 1 commit into
mainfrom
copybara/1015698193

Conversation

@copybara-service

@copybara-service copybara-service Bot commented Nov 6, 2026 •

Copy link
Copy Markdown

fix: surface backend error messages in Java and Go Interactions SDK errors

Since openapi-generation v2.960.7, Speakeasy fills the error message from error.message only for operations with a typed error schema (the Interactions *ClientError / *ServerError carriers in Java and Go). The untyped fallback (GaosApiException in Java, APIError in Go), used by operations without a typed error schema and by bodies that do not match it (e.g. the [{error: {...}}] arrays streaming endpoints return), still passes the placeholder "API error occurred" and leaves the backend's {error: {message}} only in the raw response body. So a 400 validation error from such an operation surfaces in Java as "400 . API error occurred" and in Go as APIError.Message == "API error occurred", and no Java gaos error populates ApiException.status() or carries error.details, so even typed errors read "400 . <message>".

  • Java: Emits package-private GaosErrorBody (scripts/templates/error_body.java.tmpl). GaosBaseException, GaosClientException, and GaosServerException forward GaosErrorBody.status(body) (OnePlatform error.status, else the Interactions API string error.code, else "") and GaosErrorBody.message(message, body) to com.google.genai.errors.ApiException. The message is error.message plus any error.details, appended one per line after \nDetails: ; for {error: {...}} bodies this matches the native ApiException.getErrorMessageFromBody, so gaos and native errors read the same.
  • Go: Emits messageFromBody (scripts/templates/error_body.go.tmpl) in interactions/models/apierrors/errorbody.go and calls it from NewAPIError, which fills APIError.Message from error.message.
  • Both read the {error: {...}} object and the single-element [{error: {...}}] array that streaming endpoints return, replace only the placeholder (a more specific message is kept), and keep the placeholder when the body is not a recognized JSON error (including multi-element arrays).
  • Behavior change (Java): getMessage() now spans several lines for errors that carry error.details (e.g. 400 INVALID_ARGUMENT. Bad thing\nDetails: {"@type":"type.googleapis.com/google.rpc.ErrorInfo","reason":"API_KEY_INVALID"}), so callers that log or compare the text see the extra line. message() gains the same lines: on the per-operation *ClientError / *ServerError carriers it is the message text alone (Bad thing\nDetails: …), as on the native ApiException, while GaosApiException keeps Speakeasy's existing override that returns the full getMessage() string. Go's APIError.Message stays error.message only; details remain in the body that Error() appends, following each language's native convention.
  • Documented differences from the native Java ApiException: status() falls back to the Interactions error.code where native uses the HTTP reason phrase (empty on HTTP/2); a single-element array also yields its details and an empty missing status where native throwFromErrorNode drops details and reports UNKNOWN; a multi-element array keeps the placeholder where native reads the first element. These are stated in the GaosErrorBody Javadoc and pinned by tests.
  • Sync hardening & tests: reparent_java_error replacements in sync_speakeasy_outputs.py now use _replace_once, so generator template changes fail loudly at sync time; adds patch_go_apierrors; adds Java (including parity and divergence tests against the native ApiException), Go, and sync unit tests.

@copybara-service
copybara-service Bot requested a review from a team November 6, 2026 20:41
@copybara-service copybara-service Bot changed the title fix: add typed GAOS 4XX/5XX error responses and surface backend error messages in Java, Go, and CLI fix: surface backend error messages in Java, Go, and CLI Interactions SDK errors Nov 6, 2026
@copybara-service
copybara-service Bot force-pushed the copybara/1015698193 branch 2 times, most recently from 1570a0f to 915d021 Compare November 11, 2026 22:47
@copybara-service copybara-service Bot changed the title fix: surface backend error messages in Java, Go, and CLI Interactions SDK errors fix: surface backend error messages in Java and Go Interactions SDK errors Nov 11, 2026
@copybara-service
copybara-service Bot force-pushed the copybara/1015698193 branch 2 times, most recently from ced4416 to 2444ba2 Compare November 11, 2026 23:35
…rrors

Since `openapi-generation` v2.960.7, Speakeasy fills the error message from `error.message` only for operations with a typed error schema (the Interactions `*ClientError` / `*ServerError` carriers in Java and Go). The untyped fallback (`GaosApiException` in Java, `APIError` in Go), used by operations without a typed error schema and by bodies that do not match it (e.g. the `[{error: {...}}]` arrays streaming endpoints return), still passes the placeholder `"API error occurred"` and leaves the backend's `{error: {message}}` only in the raw response body. So a 400 validation error from such an operation surfaces in Java as `"400 . API error occurred"` and in Go as `APIError.Message == "API error occurred"`, and no Java gaos error populates `ApiException.status()` or carries `error.details`, so even typed errors read `"400 . <message>"`.

- **Java**: Emits package-private `GaosErrorBody` (`scripts/templates/error_body.java.tmpl`). `GaosBaseException`, `GaosClientException`, and `GaosServerException` forward `GaosErrorBody.status(body)` (OnePlatform `error.status`, else the Interactions API string `error.code`, else `""`) and `GaosErrorBody.message(message, body)` to `com.google.genai.errors.ApiException`. The message is `error.message` plus any `error.details`, appended one per line after `\nDetails: `; for `{error: {...}}` bodies this matches the native `ApiException.getErrorMessageFromBody`, so gaos and native errors read the same.
- **Go**: Emits `messageFromBody` (`scripts/templates/error_body.go.tmpl`) in `interactions/models/apierrors/errorbody.go` and calls it from `NewAPIError`, which fills `APIError.Message` from `error.message`.
- Both read the `{error: {...}}` object and the single-element `[{error: {...}}]` array that streaming endpoints return, replace only the placeholder (a more specific message is kept), and keep the placeholder when the body is not a recognized JSON error (including multi-element arrays).
- **Behavior change (Java)**: `getMessage()` now spans several lines for errors that carry `error.details` (e.g. `400 INVALID_ARGUMENT. Bad thing\nDetails: {"@type":"type.googleapis.com/google.rpc.ErrorInfo","reason":"API_KEY_INVALID"}`), so callers that log or compare the text see the extra line. `message()` gains the same lines: on the per-operation `*ClientError` / `*ServerError` carriers it is the message text alone (`Bad thing\nDetails: …`), as on the native `ApiException`, while `GaosApiException` keeps Speakeasy's existing override that returns the full `getMessage()` string. Go's `APIError.Message` stays `error.message` only; details remain in the body that `Error()` appends, following each language's native convention.
- **Documented differences from the native Java `ApiException`**: `status()` falls back to the Interactions `error.code` where native uses the HTTP reason phrase (empty on HTTP/2); a single-element array also yields its details and an empty missing status where native `throwFromErrorNode` drops details and reports `UNKNOWN`; a multi-element array keeps the placeholder where native reads the first element. These are stated in the `GaosErrorBody` Javadoc and pinned by tests.
- **Sync hardening & tests**: `reparent_java_error` replacements in `sync_speakeasy_outputs.py` now use `_replace_once`, so generator template changes fail loudly at sync time; adds `patch_go_apierrors`; adds Java (including parity and divergence tests against the native `ApiException`), Go, and sync unit tests.

PiperOrigin-RevId: 1015698193
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants