Repository navigation
Description
Problem
bin/opencode-route-proxy.mjs parses its per-request deadline with a bare Number():
bin/opencode-route-proxy.mjs:51—const TIMEOUT_MS = Number(process.env.OPENCODE_ROUTE_PROXY_TIMEOUT_MS || 1_200_000);bin/opencode-route-proxy.mjs:535-538— the value goes straight intosetTimeout(() => deadlineCtl.abort(...), TIMEOUT_MS), the deadline that bounds every routed chat-completion request.
The proxy starts up happily with a bad value — nothing validates it — and then the deadline fires almost immediately on every request. The client gets a 502 that looks like a leaf/transport failure, the leaf is never contacted, and the route-attempt ledger records the attempt as a timeout — so the failure is misattributed to the backend pool, not to local configuration.
This is the one fleet proxy whose timeout env var did not get the strict treatment its siblings got: the listen ports all go through parseProxyPort in bin/proxy-port.mjs (#483, which exists precisely because "a bare parseInt is not a validator"), commandcode-proxy's identical timeout bug is filed as #1809, and agy-proxy's is inside #2096. The route proxy's was missed.
Evidence (verified this run, main 24ddc153)
Probe on the laptop (~/git/fleet/probe-2026-10-30-laneA-routetimeout/): the real opencode-route-proxy.mjs + proxy-port.mjs copied verbatim (md5 19286417… / 9b6fc7c1…, matching main), spawned against a fake leaf that delays 300 ms before answering, with the fixture config/ledger shape from bin/opencode-route-proxy.test.mjs:
OPENCODE_ROUTE_PROXY_TIMEOUT_MS |
Proxy starts | POST /v1/chat/completions |
Leaf hits | Ledger |
|---|---|---|---|---|
15000 (control) |
yes | 200 in 342 ms, leaf content returned | 1 | outcome success |
abc |
yes | 502 in 23 ms — leaf transport error: opencode-route-proxy deadline |
0 | outcome timeout, tag Transport |
3000000000 (> 2³¹−1) |
yes | 502 in 23 ms, same error (plus Node TimeoutOverflowWarning: the value is clamped to 1 ms) |
0 | outcome timeout, tag Transport |
-5 |
yes | 502 in 24 ms, same error | 0 | outcome timeout, tag Transport |
Mechanism: Number("abc") is NaN, and setTimeout(NaN) / setTimeout(-5) fire in ~0–1 ms; a value above 2³¹−1 is clamped by Node to 1 ms. Non-decimal spellings are silently reinterpreted instead of rejected (Number("0x493e0") = 300000, Number("1e6") = 1000000).
Why it matters
- A single typo in the one env var that tunes this proxy takes the whole routing door down while it reports itself healthy (
/healthis local and still answers 200) and blames the leaves in the ledger — the worst shape of config failure for a fleet that debugs from the ledger. - The route proxy is the routing-only door (opencode-route door must be routing-only: no OpenCode session/loop per model request #2518); its deadline is the only bound on a hung leaf attempt chain, so the value being silently wrong removes or falsifies that bound.
Acceptance criteria
-
OPENCODE_ROUTE_PROXY_TIMEOUT_MSis strictly validated at startup (decimal integer milliseconds within a stated sane range — e.g. via aproxy-port.mjs-style helper shared with the fix for commandcode-proxy: COMMANDCODE_PROXY_TIMEOUT_MS is parsed with a bare Number() — a typo'd, negative, or >2^31 value makes every request 'time out' in ~1ms instead of failing at startup #1809 if that lands first): an invalid value exits at startup with an error naming the variable and its value, likeparseProxyPortdoes for ports. - Valid values behave exactly as today (default 1,200,000 ms when unset/empty).
- Tests in
bin/opencode-route-proxy.test.mjs(or the shared helper's tests) cover at least:abc, a negative value, and a value above 2³¹−1 — each refused at startup — plus a valid small value still enforcing a real deadline against a slow leaf. - No behaviour change for any other env var or route.
Filed by new-issue-creator-code-a, 2026-10-30. Dedup: #1809 is commandcode-proxy's COMMANDCODE_PROXY_TIMEOUT_MS only; #2096 covers agy-proxy's vars; #2758 is pm-dispatch's port/host config. No existing issue mentions OPENCODE_ROUTE_PROXY_TIMEOUT_MS.
Activity
dezren39 commentedon Oct 30, 2026
🤖 Agent note · filed
abc/-5/3000000000all start healthy, then 502 every request in ~23 ms with the leaf never contacted and atimeoutledger row blaming the leaf.issue-code-routetimeout-body.md); laptop probe~/git/fleet/probe-2026-10-30-laneA-routetimeout/dezren39 commentedon Oct 30, 2026
agent-note:v1 — design-architect pass 22 (2026-10-30): ADOPTED as Phase 1 of design #2835 (bin/ proxies, with #2823/#1809/#2096): this issue's timeout parses through the NEW shared millis helper Phase 1 adds to bin/proxy-port.mjs (digits-only, 1-2^31-1, boot failure naming the variable) — not a private guard. Linked as a sub-issue of #2835 (verified in its sub_issues list). Triage: do NOT re-file/re-scope/split this issue; record the phase structure and land it as the phase, with the decisions recorded on #2835 and in its design doc (files/designs/code-env-config-strict-parse.md). This issue keeps its own queued triage packet.
3 remaining items
dezren39 commentedon Oct 30, 2026
agent-note:v1 — triaged, follow-up enqueued
dezren39 commentedon Oct 31, 2026
agent-note:v1 — picked up
dezren39 commentedon Oct 31, 2026
agent-note:v1 — done (PR opened)