{"record":{"id":"c8b87efba2823b1e","repo":"can1357/oh-my-pi","slug":"usage-reserve-reached-for-primary-model-provider","errorCode":null,"errorMessage":"Usage reserve reached for ${primary.model.provider}/${primary.model.id}; reserve policy is fail-closed.","messagePattern":"Usage reserve reached for (.+?)/(.+?); reserve policy is fail-closed\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/sdk.ts","lineNumber":2461,"sourceCode":"\t\t\t\t\t\t\tprovider: primary.model.provider,\n\t\t\t\t\t\t\tmodel: primary.model.id,\n\t\t\t\t\t\t\terror: String(error),\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\tif (usageHealth?.state === \"depleted\") {\n\t\t\t\t\t\tif (usageReservePolicy === \"fail-closed\") {\n\t\t\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\t\t`Usage depleted for ${primary.model.provider}/${primary.model.id}; reserve policy is fail-closed.`,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (modelFallbackEnabled) {\n\t\t\t\t\t\t\tusageFallbackTriggered = true;\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif (usageHealth?.state === \"reserve\") {\n\t\t\t\t\t\tif (usageReservePolicy === \"fail-closed\") {\n\t\t\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\t\t`Usage reserve reached for ${primary.model.provider}/${primary.model.id}; reserve policy is fail-closed.`,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\tmodelFallbackEnabled &&\n\t\t\t\t\t\t\t(usageReservePolicy === \"auto\" || (!options.hasUI && !options.deferUsageReserveConfirmation))\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\tusageFallbackTriggered = true;\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tlet selectedModel = primary.model;\n\t\t\t\tlet selectedThinkingLevel = primary.thinkingLevel;\n\t\t\t\tlet selectedExplicitThinkingLevel = primary.explicitThinkingLevel;\n\t\t\t\t// A chain entry without its own `:level` suffix inherits the\n\t\t\t\t// unavailable primary's configured thinking level, matching\n\t\t\t\t// runtime fallback-chain semantics.","sourceCodeStart":2443,"sourceCodeEnd":2479,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/sdk.ts#L2443-L2479","documentation":"When the provider's usage health reports \"reserve\" (remaining usage has dropped into the reserve threshold) and usageReservePolicy is \"fail-closed\", the SDK refuses to start the session rather than risk mid-session exhaustion.","triggerScenarios":"createAgentSession with usageReservePolicy \"fail-closed\" while primary model provider usage state is \"reserve\" and fallback conditions (modelFallbackEnabled with \"auto\" or headless confirmation settings) are not met.","commonSituations":"Provider balance close to exhaustion; strict CI policy configured; interactive UI present but deferUsageReserveConfirmation set so automatic fallback is skipped.","solutions":["Restore provider quota/credits to move usage out of the reserve state","Set usageReservePolicy to \"auto\" or \"warn\" to allow fallback/continuation","Enable modelFallbackEnabled (or allow usage-reserve confirmation via hasUI/deferUsageReserveConfirmation settings) so the session can switch models"],"exampleFix":"// before\nawait createAgentSession({ usageReservePolicy: \"fail-closed\", hasUI: false, ... });\n// after\nawait createAgentSession({ usageReservePolicy: \"auto\", modelFallbackEnabled: true, ... });","handlingStrategy":"fallback","validationCode":"const health = await getUsageHealth(primaryModel);\nif (health?.state === \"reserve\") console.warn(\"provider usage in reserve threshold\");","typeGuard":"null","tryCatchPattern":"try {\n  session = await createAgentSession(options);\n} catch (err) {\n  if (err instanceof Error && err.message.startsWith(\"Usage reserve reached\")) {\n    session = await createAgentSession({ ...options, usageReservePolicy: \"auto\", modelFallbackEnabled: true });\n  } else throw err;\n}","preventionTips":["Set usageReservePolicy to \"auto\" when automatic fallback is acceptable","Enable modelFallbackEnabled so reserve states can trigger a model switch","Avoid deferUsageReserveConfirmation in headless mode unless fail-closed is intended"],"tags":["quota","usage","configuration"],"backgroundTag":"quota-exceeded","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}