Skip to content

fix(ai-gateway): distinguish client disconnects from upstream disconnects - #4795

Merged
chrarnoldus merged 1 commit into
mainfrom
fix/clarify-client-vs-upstream-disconnect
Jul 27, 2026
Merged

fix(ai-gateway): distinguish client disconnects from upstream disconnects#4795
chrarnoldus merged 1 commit into
mainfrom
fix/clarify-client-vs-upstream-disconnect

Conversation

@chrarnoldus

Copy link
Copy Markdown
Contributor

Problem

When a client disconnects mid-request, the request signal is forwarded to the upstream fetch, so the fetch aborts too. The gateway logged AI gateway client disconnected and then immediately returned The upstream provider disconnected before sending a response. — implying an upstream fault that never happened.

The same message was also used for gateway-side timeouts (no response headers within 15 minutes), which is a different failure.

Changes

  • upstream-request.ts: when the fetch fails while the caller's signal is aborted (and the failure is an abort, or classification itself failed), return a dedicated client_disconnect response with HTTP 499 and the message "The client disconnected before the upstream provider responded, so the request was cancelled. The upstream provider did not fail." 499 keeps these cancellations out of upstream 5xx error rates.
  • Genuine upstream failures now get two distinct messages: "The upstream provider did not send response headers before the gateway timeout." for the timeout families, and "The upstream provider closed the connection before sending a response." otherwise. Both keep error_type: upstream_disconnect and HTTP 503.
  • The 15-minute timeout listener log now states that it is a gateway timeout waiting for response headers, including the timeout value.
  • route.ts: the client-disconnect log now says it is aborting in-flight upstream work, with a comment recording that any abort logged afterwards for that request is a consequence of the disconnect.
  • Added client_disconnect to ProxyErrorType.

Sentry/console reporting behaviour is unchanged: client-caused aborts are still not captured as upstream fetch failures.

Verification

  • pnpm --filter web test -- src/tests/openrouterApi.timeout.test.ts (extended with client-disconnect, gateway-timeout, and connection-close response assertions)
  • pnpm --filter web test -- src/app/api/openrouter
  • pnpm --filter web typecheck, pnpm --filter web lint, pnpm format

…ects

A client going away aborts the upstream fetch through the forwarded request
signal, so those cancellations were reported as "The upstream provider
disconnected before sending a response" right after logging the client
disconnect. Return a dedicated 499 client_disconnect response for that case,
split the upstream message into timeout and connection-close variants, and
note in the client-disconnect log that later aborts follow from it.
@chrarnoldus chrarnoldus self-assigned this Jul 27, 2026
@kilo-code-bot

kilo-code-bot Bot commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Code Review Summary

Status: No Issues Found | Recommendation: Merge

Executive Summary

Reviewed the client-disconnect vs. upstream-disconnect classification changes across the gateway route, upstream fetch handling, error-type enum, and tests, and found no high-confidence bugs, security issues, or logic errors in the changed lines.

Files Reviewed (4 files)
  • apps/web/src/app/api/openrouter/[...path]/route.ts
  • apps/web/src/lib/ai-gateway/providers/upstream-request.ts
  • apps/web/src/lib/proxy-error-types.ts
  • apps/web/src/tests/openrouterApi.timeout.test.ts

Reviewed by claude-sonnet-5 · Input: 16 · Output: 5K · Cached: 404.7K

Review guidance: REVIEW.md from base branch main

@chrarnoldus
chrarnoldus merged commit c9095e6 into main Jul 27, 2026
15 checks passed
@chrarnoldus
chrarnoldus deleted the fix/clarify-client-vs-upstream-disconnect branch July 27, 2026 14:37
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.

3 participants