Skip to content

fix(gateway): reject uncorrelated HTTP JSON-RPC errors - #689

Merged
jmagar merged 7 commits into
mainfrom
fix/upstream-http-error-propagation-20260916
Sep 19, 2026
Merged

jmagar merged 7 commits into
mainfrom
fix/upstream-http-error-propagation-20260916

Conversation

@jmagar

@jmagar jmagar commented Sep 17, 2026

Copy link
Copy Markdown
Collaborator

Summary

Reject non-2xx JSON-RPC error responses unless the response id exactly matches the request Labby just sent.

The custom Streamable HTTP adapter previously accepted any non-2xx body that parsed as a JSON-RPC error. A malformed upstream error such as {"jsonrpc":"2.0","id":null,"error":...} was returned to rmcp as a successful transport response even when the pending request had id 1. rmcp could not correlate that response, so the pending request stayed orphaned until Labby's outer Code Mode timeout (~59 s).

This was reproduced against ExGPT: an immediate upstream HTTP 500 with id:null was surfaced by Labby as a one-minute timeout.

The adapter now captures the outbound JSON-RPC id before sending and only treats a non-success JSON-RPC error as a protocol response when its id exactly matches. Null or mismatched ids fall through to the existing sanitized terminal HTTP transport error path.

Security / correctness properties

  • matching error id: preserve the upstream JSON-RPC error
  • null error id: fail the send immediately
  • wrong non-null error id: fail the send immediately
  • non-JSON error bodies remain sanitized and are never exposed
  • successful response behavior is unchanged

Verification

  • cargo fmt --all
  • cargo test -p labby-gateway --lib non_success_jsonrpc_error --locked → 3 passed
  • cargo test -p labby-gateway --lib upstream::http_client::tests --locked → 32 passed
  • git diff --check

Clippy with -D warnings is currently blocked by pre-existing warnings in untouched labby-gateway/code-mode files (for example unused_async_trait_impl and result_large_err); this change introduces no new clippy diagnostic in http_client.rs.

Related upstream bug

The incident also exposed a separate MCP Elixir SDK bug that emitted data: :absent, causing its response budget to falsely report response_too_large. That fix is isolated in dinglebear-ai/mcp-elixir-sdk#9. This Labby change remains valuable defensively even after that SDK fix because upstreams must never be allowed to orphan or cross-correlate pending requests with null/wrong ids.

@jmagar
jmagar enabled auto-merge (squash) September 19, 2026 02:33
@jmagar
jmagar merged commit b313a86 into main Sep 19, 2026
70 checks passed
@jmagar
jmagar deleted the fix/upstream-http-error-propagation-20260916 branch September 19, 2026 06:55
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