You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
When retry.provider.maxRetries > 0, pi-ai passes that value into the OpenAI/Anthropic SDK maxRetries option. Those SDKs:
treat every HTTP 429 as retryable
sleep the fullRetry-After with no delay cap
use a plain setTimeout sleep that ignores AbortSignal
So a usage-limit 429 with a multi-day Retry-After freezes the agent on working, and Escape cannot interrupt.
This is separate from the provider actually being out of quota: the provider correctly returns 429, but Pi's handling makes the failure look like a hang.
// openai/client.mjs retryRequesttimeoutMillis=timeoutSeconds*1000;// full Retry-After, no capawaitsleep(timeoutMillis);
Pi Escape calls agent.abort() → AbortSignal, but the SDK retry sleep does not listen to it.
Expected
Usage-limit / multi-day Retry-After should surface as a normal error immediately (or within agent-level abortable backoff).
Escape must be able to cancel provider waits.
retry.provider.maxRetryDelayMs must actually bound provider waits, or SDK retries must stay disabled.
Related
fix(ai): disable hidden provider 429 retries #4991 disabled default SDK retries (maxRetries ?? 0) but still forwarded explicit options.maxRetries from coding-agent settings, which reopens this hole when users set retry.provider.maxRetries > 0.
Docs already warn to keep provider maxRetries at 0, but a mis-set value currently freezes the session instead of failing closed.
Suggested fix
Always force OpenAI/Anthropic SDK maxRetries: 0. Keep abortable agent-level retry, which already classifies terminal quota/billing/usage-limit errors as non-retryable.
Summary
When
retry.provider.maxRetries > 0, pi-ai passes that value into the OpenAI/Anthropic SDKmaxRetriesoption. Those SDKs:Retry-Afterwith no delay capsetTimeoutsleep that ignores AbortSignalSo a usage-limit 429 with a multi-day
Retry-Afterfreezes the agent on working, and Escape cannot interrupt.This is separate from the provider actually being out of quota: the provider correctly returns 429, but Pi's handling makes the failure look like a hang.
Reproduction
Provider evidence (OpenCode Go)
Observed:
{ "type": "error", "error": { "type": "GoUsageLimitError", "message": "Monthly usage limit reached. Resets in 3 days. ..." } }With the OpenAI client (
maxRetries: 0) this fails in ~800ms.With
maxRetries: 2(as configured via Pi settings) the client starts sleeping ~3 days.Pi evidence
pi --provider opencode-go --model kimi-k3 --no-session --no-tools -p "hi"sleep(retry-after)Root settings that re-enable the hole (defaults are safer):
{ "retry": { "provider": { "maxRetries": 2, "maxRetryDelayMs": 60000 } } }maxRetryDelayMsis not applied on the openai-completions path; only some custom transports (e.g. Codex) cap delays.Why Escape fails
OpenAI SDK:
Pi Escape calls
agent.abort()→ AbortSignal, but the SDK retry sleep does not listen to it.Expected
retry.provider.maxRetryDelayMsmust actually bound provider waits, or SDK retries must stay disabled.Related
maxRetries ?? 0) but still forwarded explicitoptions.maxRetriesfrom coding-agent settings, which reopens this hole when users setretry.provider.maxRetries > 0.Suggested fix
Always force OpenAI/Anthropic SDK
maxRetries: 0. Keep abortable agent-level retry, which already classifies terminal quota/billing/usage-limit errors as non-retryable.PR incoming.