[Bug] -p batch mode hangs on a 429 with a long reset; unknown settings keys are silently accepted
#1474
Replies: 1 comment
|
Follow-up: I traced finding 2 and it has a concrete mechanism, which also corrects how I framed the request above. The cap is not implemented. What happens instead. The vendored Stainless SDKs — const retryAfterHeader = responseHeaders?.get("retry-after");
if (retryAfterHeader && !timeoutMillis) {
const timeoutSeconds = parseFloat(retryAfterHeader);
if (!Number.isNaN(timeoutSeconds)) timeoutMillis = timeoutSeconds * 1e3;
}
...
await sleep(timeoutMillis);
return this.makeRequest(options, retriesRemaining - 1, requestLogID);Unbounded, at The number. Re-measured today against the still-cooled route: Seconds — so Correcting my own request 2. I asked for the cap to be treated as terminal in batch mode too, which implied it worked interactively and merely missed the headless path. That was wrong — it is not enforced anywhere, for any provider or mode. The accurate request is: implement the cap at the point where a server-requested delay is turned into a sleep, and fail with an informative error above it, as Requests 1 (reject unknown settings keys) and 3 (ordered I have posted the same evidence on #1405, where it distinguishes two mechanisms converging on one symptom: this returned-429 sleep, and the unbounded stream read that report describes for OAuth exhaustion where no Caveat on method: this comes from reading the installed 0.7.2 bundle plus |
Uh oh!
There was an error while loading. Please reload this page.
Summary
Affected area: settings validation, provider retry/backoff, and non-interactive (
-p) batch runs.Two findings from one incident. They are separable, but they compound: the settings key I expected to provide failover turned out to be inert, so a single provider cooldown had nothing to fall back to — and instead of failing, the batch run hung until I killed it.
This is closely related to #1405 (terminal quota response leaves the TUI on
Waiting). That report covers OAuth subscription exhaustion in the interactive TUI; what I hit is the API-key429-with-long-reset variant in-pbatch mode. The user-visible rule @sankks11 proposed there — a terminal limit should end the request and surface any reset information — would cover my case too, so these may share a fix.Environment
api: openai-completions, custommodels.jsonproviders)Finding 1 — unknown settings keys are silently accepted
settings.jsoncontained afallbackModelsarray. It validated cleanly, emitted no warning, and did nothing.The key appears 0 times in the shipped
dist/bundle. Control greps against the same bundle, to show the method finds keys that do exist:dist/bundlefallbackModelsrlmMaxDepthautoRefinesteeringModeBecause unknown keys are accepted without complaint, a harness can appear failover-protected while having no failover at all. The same silence would swallow a typo, or a key removed in a later release — the config keeps validating and the behavior quietly disappears.
Suggestion: reject unknown settings keys, or warn loudly on load. Silent acceptance turns config drift into invisible no-ops with operational consequences.
Finding 2 — a 429 with a long advertised reset hangs batch mode
The sole configured default model began returning HTTP
429with a long advertised reset (~102 hours — a provider-family cooldown).A
prime-agent -p "..."batch run then produced zero output and never exited. I killed it externally after 240s. The daemon log ends at:retry.provider.maxRetryDelayMswas30000. Per the settings documentation, a server-requested delay above that cap should "fail immediately with an informative error" — but the run hung instead of surfacing a terminal error.Control: the same run with
--provider/--modelpointed at a healthy route exited0immediately. The failure is isolated to the dead route plus the absent failover, not to the prompt or the harness invocation.Suggestion: treat a retry delay above
retry.provider.maxRetryDelayMsas terminal in batch mode as well as interactive — a429carrying an hours-long reset should end the turn with a structured failure and a non-zero exit, not a silent hang. A hang is materially worse than an error for unattended runs: it consumes the whole wall-clock budget and produces nothing to act on.Related feature interest
Ordered, health-gated
fallbackModelsacross configured providers would let long-running and autonomous work survive a provider cooldown without an external wrapper. I have kept that out of the two bug findings above deliberately — happy to move it to Feature requests if that is the better home for it.I am currently working around this with an external wrapper that health-probes a cross-provider chain before and between attempts.
Offer
I have a working patch for the failover piece on a fork branch (
thomaswillner/prime-agent@eb6f1ab, 19 files). I am not requesting that it be reviewed or merged — I understand from CONTRIBUTING.md that implementation happens on maintainer invitation, and I opened it before reading that, which was my mistake. Flagging it only so the work is visible if it is useful.Happy to supply the full reproduction evidence — bundle greps, daemon logs, proxy responses — or to re-test any proposed fix against the same 429 route.
All reactions