Skip to content

feat: clearer OHTTP client error messages - #785

Open
kilianglas wants to merge 3 commits into
mainfrom
improve-ohttp-error-messages
Open

feat: clearer OHTTP client error messages#785
kilianglas wants to merge 3 commits into
mainfrom
improve-ohttp-error-messages

Conversation

@kilianglas

Copy link
Copy Markdown
Contributor

Summary

Improves the accuracy of error messages surfaced on the OHTTP request path in the authenticator. Today, non-crypto failures are misattributed to OHTTP crypto — e.g. a target service being unreachable surfaces as a cryptic "decapsulation" error, and a captive portal returning a 200 HTML page also fails as an opaque decapsulation error.

All changes are server-agnostic and do not depend on matching the server's error body (so they remain portable across any RFC 9458 gateway). No server change is required.

Changes

  • Split decapsulation from encapsulation errorsOhttpEncapsulationError previously printed "encapsulation error" for both encrypt and decrypt failures. Added a dedicated OhttpDecapsulationError so a failed decrypt is labelled accurately.
  • Content-type guard before decapsulation — a 2xx relay response that is not message/ohttp-res (loose, case-insensitive match) now returns OhttpRelayInvalidResponse instead of a cryptic decap failure. The gateway only sets that content-type on success, so this is provably a relay-leg condition — most commonly a captive portal / transparent proxy intercepting the client network.
  • Relay errors carry scope + relay URLOhttpRelayError now includes the service scope and relay_url, and its message reflects that a non-2xx outer response means the request was rejected before decapsulation (relay leg, or the gateway's RFC 9458 §5.2 pre-decap plaintext rejections such as a 401 key/config mismatch).
  • Inner 502/503/504 → service unavailable — inner statuses that signal an unreachable/overloaded upstream now map to a clear ServiceUnavailable error rather than a raw 5xx body. RFC 9458 §5.2 uses 504 for a gateway that cannot reach its target; this installs the correct client behaviour now (no effect on the current gateway, which returns 500, until a server follow-up lands).

Out of scope

The headline "target-unreachable shows as decapsulation" symptom is not client-fixable: RFC 9458 §5.2 mandates that post-decapsulation and target errors be encapsulated (inner response, outer 200), so there is no outer-layer signal. The portable fix is server-side — emit a distinct inner status (504, not 500) for target-unreachable — and is recommended as a follow-up on the gateway.

Tests

  • Pure unit test for the loose message/ohttp-res matcher.
  • mockito-based request-path tests: relay non-2xx → OhttpRelayError (scope + URL populated); 2xx non-OHTTP content-type → OhttpRelayInvalidResponse; correct content-type with an undecryptable body → OhttpDecapsulationError.

@kilianglas
kilianglas requested a review from a team as a code owner June 14, 2026 09:13
@paolodamico

Copy link
Copy Markdown
Collaborator

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b8e415cd35

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +107 to +111
if matches!(
resp.status,
StatusCode::BAD_GATEWAY | StatusCode::SERVICE_UNAVAILABLE | StatusCode::GATEWAY_TIMEOUT
) {
return AuthenticatorError::ServiceUnavailable {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve structured 503/504 service errors

When the gateway or indexer themselves time out, their routers install timeout_layer(... request_timeout(...)), which returns a structured JSON RequestTimeout body with HTTP 504, and the gateway also uses HTTP 503 for its typed BatcherUnavailable response. This new status-only shortcut runs before decoding the body, so those first-party service errors are now collapsed into ServiceUnavailable and callers lose the precise error code/message that was previously available via GatewayError/IndexerError. Consider parsing the structured service body first, or only falling back to ServiceUnavailable for opaque infra responses.

Useful? React with 👍 / 👎.

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.

2 participants