can1357/oh-my-pi · error
${USAGE_PREFLIGHT_BLOCKED_PREFIX} ${condition} for ${current
Error message
${USAGE_PREFLIGHT_BLOCKED_PREFIX} ${condition} for ${currentSelector}; reserve policy is fail-closed. What it means
TurnRecovery performs a usage preflight before retrying a turn against a model (identified by currentSelector). When the health check reports 'reserve' (usage reserve reached) or depleted usage and the `retry.usageReservePolicy` setting is 'fail-closed', it throws immediately with the USAGE_PREFLIGHT_BLOCKED_PREFIX message — the retry is refused rather than spending tokens that may not be covered.
Source
Thrown at packages/coding-agent/src/session/turn-recovery.ts:1575
health.accounts.some(account => account.state === "healthy")
) {
this.#host.modelRegistry.authStorage.releaseSessionCredentialForReselection(
currentModel.provider,
this.#host.sessionId(),
);
}
return false;
}
if (health.state === "unknown") {
this.#usageReserveApprovedSelector = undefined;
return false;
}
if (health.state !== "reserve") this.#usageReserveApprovedSelector = undefined;
const reservePolicy = this.#host.settings.get("retry.usageReservePolicy");
if (reservePolicy === "fail-closed") {
const condition = health.state === "reserve" ? "reserve reached" : "usage depleted";
throw new Error(
`${USAGE_PREFLIGHT_BLOCKED_PREFIX} ${condition} for ${currentSelector}; reserve policy is fail-closed.`,
);
}
if (
reservePolicy === "confirm" &&
health.state === "reserve" &&
this.#usageReserveApprovedSelector === currentSelector
) {
return false;
}
if (!this.#host.settings.get("retry.modelFallback")) return false;
let fallback: { role: string; selector: RetryFallbackSelector; apiKey: string } | undefined;
const ceiling = this.#host.thinkingLevelCeiling();
const chainKeys = this.retryFallbackChainKeys(currentSelector, currentModel);
for (const role of chainKeys) {
for (const candidate of this.findRetryFallbackCandidates(role, currentSelector, currentModel)) {
if (this.isRetryFallbackSelectorSuppressed(candidate)) continue;View on GitHub (pinned to 9690622007)
Solutions
- Free up quota: wait for the usage window to reset or top up credits/quota for the model selector.
- Switch model to a selector with available reserve (retry with a different model).
- Change retry.usageReservePolicy from 'fail-closed' to 'confirm' or a permissive policy if overspend is acceptable — set it in host settings.
- Catch errors with USAGE_PREFLIGHT_BLOCKED_PREFIX and stop the run gracefully instead of looping retries.
Example fix
// before
await session.retry(); // throws when reserve is hit under fail-closed
// after: relax the policy or guard
settings.set('retry.usageReservePolicy', 'confirm');
await session.retry(); Defensive patterns
Strategy: try-catch
Validate before calling
// before retrying, check the policy and stop early
const policy = settings.get('retry.usageReservePolicy');
if (policy === 'fail-closed' && usageRemaining(selector) <= 0) {
return; // don't attempt the retry
} Try / catch
const PREFIX = 'usage preflight blocked';
try {
await turnRecovery.retry();
} catch (err) {
if (err instanceof Error && err.message.startsWith(PREFIX)) {
logger.warn('retry blocked by usage reserve policy', { msg: err.message });
return; // stop cleanly; do not loop retries
}
throw err;
} Prevention
- Monitor usage/health state and stop runs before the reserve is exhausted.
- Choose retry.usageReservePolicy deliberately: fail-closed for unattended jobs, confirm for interactive use.
- Configure fallback model selectors with remaining quota.
- Alert on preflight-blocked messages so quota can be topped up promptly.
When it happens
Trigger: A turn retry attempt while `#host.settings.get('retry.usageReservePolicy')` === 'fail-closed' and health.state is 'reserve' or usage is depleted for currentSelector (turn-recovery.ts:1571-1577).
Common situations: Long agent sessions exhausting the usage reserve with the default fail-closed policy; API quota nearly spent mid-batch; running unattended jobs where spend must not exceed the reserve.
Related errors
- Usage depleted for ${primary.model.provider}/${primary.model
- Usage reserve reached for ${primary.model.provider}/${primar
- using '-' to denote standard input does not work in file sys
- V2 remote compaction failed (${response.status} ${response.s
- Anthropic cache refresh response omitted usage
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/ec8a40f4a7b4cd96.
Report an issue: GitHub.