Skip to content

fix(relay): send a failed direct fallback only once - #469

Merged
ualtinok merged 3 commits into
mainfrom
fix/relay-direct-fallback-once
Oct 24, 2026
Merged

ualtinok merged 3 commits into
mainfrom
fix/relay-direct-fallback-once

Conversation

@antauth-alfonso

Copy link
Copy Markdown

While diagnosing last night's mutation-audit baseline failure, a real duplicate-send path turned up in sendViaRelay. The relay's HTTP 5xx and relay-401 branches (and the WebSocket→HTTP path) call the direct fallback, and if that direct send rejected after it went out (for example a connection reset after Anthropic received it), the outer catch fell back a second time: two physical sends for one request. The fallback now runs at most once per request; a failure after it started is passed to the caller, which retries with its own backoff. A relay failure before any fallback still falls back once. Red-first Core tests and a mutation row.

The CI failure itself was test-only: an earlier WebSocket test overran Bun's timeouts and its late reset re-enabled profile fetching, so the relay-fallback test's catch-all mock counted a profile GET as a second direct send. That test now counts only its own sends.

The relay-fallback quota test counted every non-relay request that reached
its fetch mock as a direct send. When the WebSocket relay test before it
overran Bun's test and hook timeouts, that test's late teardown deleted
OPENCODE_ANTHROPIC_AUTH_DISABLE_PROFILE_HYDRATION during this test, so its
plugin also sent GET /api/oauth/profile and the count read 2 (nightly audit
run 40076898210). With a longer overrun, the earlier test's own relay and
direct requests reached this mock too.

Direct sends now count only POSTs to the messages endpoint whose body
carries this request's probe text, and relay sends count only payloads with
this request's affinity. 'Exactly once' still means once for this request:
a relay mutation that calls the direct fallback twice still fails it.
sendRelayHttp calls the direct fallback itself on a relay 5xx and on a
relay-only 401. When that direct request failed after it started (for
example a connection reset after the body reached Anthropic), its error
reached sendViaRelay's outer catch, which, with fallbackToDirect on,
called the fallback again: one request, two direct sends, possibly billed
twice. The WebSocket -> HTTP relay path ended in the same catch.

sendViaRelay now records when its direct fallback has started and rethrows
that fallback's own error instead of sending again. A relay that fails
before any fallback started still falls back direct once, as before.

Red first: the three new 'is not sent again' tests failed with 2 direct
sends before this change. Mutation row relay-direct-fallback-sends-once
removes the guard and reddens exactly those three.
@ualtinok
ualtinok merged commit 9aab567 into main Oct 24, 2026
20 checks passed
@ualtinok
ualtinok deleted the fix/relay-direct-fallback-once branch October 24, 2026 11:44
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