unslothai/unsloth · error · CodexAuthError
Authorization flow was not found or expired.
Error message
Authorization flow was not found or expired.
What it means
Raised as CodexAuthError by get_flow on the first branch: the in-memory flow exists and matches the provider, but it is a detached/persisted flow (no live server, task, or persist callback) and reloading it from the persistence layer (_load_persisted_oauth_flow) returns None. The stale in-memory entry is then popped. In practice: the flow you are asking for no longer exists on disk.
Source
Thrown at studio/backend/core/inference/openai_codex_auth.py:588
"expires_at": int(flow.expires_at),
"authorization_url": flow.authorization_url or None,
"verification_url": flow.verification_url or None,
"user_code": flow.user_code or None,
"message": flow.message or None,
}
def get_flow(provider_id: str, flow_id: str) -> OAuthFlow:
flow = _flows.get(flow_id)
if (
flow is not None
and flow.provider_id == provider_id
and (flow.server is None and flow.task is None and flow.persist_bundle is None)
):
persisted = _load_persisted_oauth_flow(provider_id, flow_id)
if persisted is None:
_flows.pop(flow_id, None)
raise CodexAuthError("Authorization flow was not found or expired.")
flow = persisted
_flows[flow.id] = flow
elif flow is None or flow.provider_id != provider_id:
flow = _load_persisted_oauth_flow(provider_id, flow_id)
if flow is None:
raise CodexAuthError("Authorization flow was not found or expired.")
_flows[flow.id] = flow
if time.time() >= flow.expires_at and flow.status == "pending":
flow.status = "error"
flow.message = "Authorization expired. Start a new connection."
if flow.task:
flow.task.cancel()
if flow.server:
flow.server.close()
return flow
async def complete_browser_flow(provider_id: str, flow_id: str, callback_url: str) -> OAuthFlow:View on GitHub (pinned to 203007d190)
Solutions
- Start a new authorization flow and use its fresh flow_id.
- Invalidate stored flow_ids in the UI whenever the backend restarts or the provider is disconnected.
- If multi-worker, ensure all workers share the same installation DB so persisted flows are visible.
- Check whether a cleanup task or TTL sweeper deleted the record before the client polled.
Example fix
// before
flow = codex_auth.get_flow(provider_id, flow_id_from_yesterday)
// after
try:
flow = codex_auth.get_flow(provider_id, flow_id_from_yesterday)
except codex_auth.CodexAuthError:
flow = await codex_auth.start_browser_flow(provider_id, persist_bundle) # mint a new flow Defensive patterns
Strategy: validation
Validate before calling
flow = None
try:
flow = codex_auth.get_flow(provider_id, flow_id)
except codex_auth.CodexAuthError:
flow = None
if flow is None:
flow = await start_new_flow(provider_id) # never reuse an unresolvable flow_id Type guard
def flow_exists(provider_id: str, flow_id: str) -> bool:
try:
codex_auth.get_flow(provider_id, flow_id)
return True
except codex_auth.CodexAuthError:
return False Try / catch
try:
flow = codex_auth.get_flow(provider_id, flow_id)
except codex_auth.CodexAuthError as exc:
if "not found or expired" in str(exc):
return RedirectResponse("/connect/chatgpt") # restart UX
raise Prevention
- Discard flow ids on backend restart or provider disconnect.
- Ensure workers share one installation DB so persisted flows are visible to all.
- Handle 'not found or expired' as a 404-style restart, not a retry.
- Key stored flow ids by provider_id to avoid mismatches.
When it happens
Trigger: Calling get_flow/complete_browser_flow with a flow_id from a previous Studio session after the persisted flow record was deleted, expired and cleaned up, or never committed; multiple workers where one deleted the DB row; the flows table was reset.
Common situations: Frontend holds a stale flow_id after a backend restart or DB clear; the user disconnected the provider which removed persisted flows; a different worker processed and deleted the flow first.
Related errors
- Authorization flow was cancelled before credentials were sav
- Authorization flow is no longer active.
- ChatGPT credential update is busy. Please retry.
- ChatGPT returned an invalid access token.
- The ChatGPT account identifier was missing.
AI-assisted analysis of unslothai/unsloth@203007d190 (2026-08-15).
Data as JSON: /api/errors/800a500a85d56139.
Report an issue: GitHub.