Observed live on both worker boxes on 2026-08-29 (worker build 604c428c). Every dispatched task died at its first model call. The tasks were not retried and not backed off — each was burned immediately.
What the provider actually returned
402: {"message":"This request would exceed your available credits given your current
in-flight requests. Retry after in-flight requests settle, or add credits.",
"code":402,"metadata":{"reason":"in_flight_budget_exhausted",
"limit_source":"openrouter_in_flight_budget",
"remedy_hint":"Retry after your in-flight requests settle (see the Retry-After header). ...",
"headers":{"Retry-After":"120"}}}
Note the shape: a Retry-After header, and a remedy that begins "Retry after your in-flight requests settle". OpenRouter is describing a transient concurrency/budget cap, semantically much closer to a 429 than to "your account is empty".
Why it is classified as terminal
vinci/extensions/vinci-provider.ts:24 matches any 402 as budget-exhausted:
/\b402\b|budget[_ -]?exhausted|insufficient[_ -]?quota|out of credits?|.../i
Two independent clauses fire here — the bare \b402\b, and budget[_ -]?exhausted, which matches the literal string in_flight_budget_exhausted. vinci/extensions/vinci-model-provenance.ts:132 likewise returns "account" for status === 402, and vinci/test/no-downgrade-integration.mjs:29 states the assumption outright: "402 is out of credit".
That assumption is right for a genuine out-of-credit 402 and the no-downgrade behaviour built on it is correct — silently falling back to a cheaper model on a billing failure is exactly what should not happen. The defect is that two different 402s are conflated. One is terminal; the other ships a Retry-After and asks to be retried.
Measured impact
| run |
boxes |
dispatched |
FAILED |
spend |
| night3 |
box-1 + box-2 |
4 |
2 |
$0.021 |
| night3ab |
box-1 only |
1 |
1 |
$0.001 |
Reproduced at single-box, one in-flight request, so this is not only a concurrency artifact — but that also means the honest fix is not "retry forever". With a depleted balance a bounded retry still fails; what changes is that a recoverable dip (in-flight settling, a top-up landing mid-run) stops costing the whole queue.
Boxes were otherwise healthy throughout: build 604c428c on both, vinci-worker-daemon.service active, claim directories and live pids observed.
Ask
Split the classification:
metadata.reason === "in_flight_budget_exhausted" (or any 402 carrying Retry-After) → retryable; honour the header with bounded backoff and a retry ceiling, then go terminal.
- 402 without those markers → terminal out-of-credit, unchanged, still no downgrade.
vinci/extensions/vinci-provider.ts:153-154 already honours retry-after on the rate-limited path, so the mechanism exists; the 402 path just never reaches it.
Second, smaller observation — reported as unconfirmed
On both failures the task record disagrees with itself: outcome.state = "BLOCKED" while the task-level state = "FAILED" with exit_code: 1. Night 2 recorded BLOCKED outcomes as BLOCKED task states (3 of 72), so the mapping is not unconditionally lossy. I have not read the mapping code and am not asserting a defect — flagging it as worth a look, since a blocked-vs-failed mislabel changes what the endurance exit criteria count.
Repro: dispatch any worker task while the OpenRouter balance is below the in-flight budget threshold; inspect /var/lib/vinci-worker/tasks/<id>.json.
Observed live on both worker boxes on 2026-08-29 (worker build
604c428c). Every dispatched task died at its first model call. The tasks were not retried and not backed off — each was burned immediately.What the provider actually returned
Note the shape: a
Retry-Afterheader, and a remedy that begins "Retry after your in-flight requests settle". OpenRouter is describing a transient concurrency/budget cap, semantically much closer to a 429 than to "your account is empty".Why it is classified as terminal
vinci/extensions/vinci-provider.ts:24matches any 402 as budget-exhausted:Two independent clauses fire here — the bare
\b402\b, andbudget[_ -]?exhausted, which matches the literal stringin_flight_budget_exhausted.vinci/extensions/vinci-model-provenance.ts:132likewise returns"account"forstatus === 402, andvinci/test/no-downgrade-integration.mjs:29states the assumption outright: "402 is out of credit".That assumption is right for a genuine out-of-credit 402 and the no-downgrade behaviour built on it is correct — silently falling back to a cheaper model on a billing failure is exactly what should not happen. The defect is that two different 402s are conflated. One is terminal; the other ships a
Retry-Afterand asks to be retried.Measured impact
Reproduced at single-box, one in-flight request, so this is not only a concurrency artifact — but that also means the honest fix is not "retry forever". With a depleted balance a bounded retry still fails; what changes is that a recoverable dip (in-flight settling, a top-up landing mid-run) stops costing the whole queue.
Boxes were otherwise healthy throughout: build
604c428con both,vinci-worker-daemon.serviceactive, claim directories and live pids observed.Ask
Split the classification:
metadata.reason === "in_flight_budget_exhausted"(or any 402 carryingRetry-After) → retryable; honour the header with bounded backoff and a retry ceiling, then go terminal.vinci/extensions/vinci-provider.ts:153-154already honoursretry-afteron the rate-limited path, so the mechanism exists; the 402 path just never reaches it.Second, smaller observation — reported as unconfirmed
On both failures the task record disagrees with itself:
outcome.state = "BLOCKED"while the task-levelstate = "FAILED"withexit_code: 1. Night 2 recorded BLOCKED outcomes as BLOCKED task states (3 of 72), so the mapping is not unconditionally lossy. I have not read the mapping code and am not asserting a defect — flagging it as worth a look, since a blocked-vs-failed mislabel changes what the endurance exit criteria count.Repro: dispatch any worker task while the OpenRouter balance is below the in-flight budget threshold; inspect
/var/lib/vinci-worker/tasks/<id>.json.