Skip to content

A retryable OpenRouter 402 (in_flight_budget_exhausted, Retry-After: 120) is classified as terminal out-of-credit #33

Description

@thegeorgepu

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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions