{"record":{"id":"800a500a85d56139","repo":"unslothai/unsloth","slug":"authorization-flow-was-not-found-or-expired","errorCode":null,"errorMessage":"Authorization flow was not found or expired.","messagePattern":"Authorization flow was not found or expired\\.","errorType":"exception","errorClass":"CodexAuthError","httpStatus":400,"severity":"error","filePath":"studio/backend/core/inference/openai_codex_auth.py","lineNumber":588,"sourceCode":"        \"expires_at\": int(flow.expires_at),\n        \"authorization_url\": flow.authorization_url or None,\n        \"verification_url\": flow.verification_url or None,\n        \"user_code\": flow.user_code or None,\n        \"message\": flow.message or None,\n    }\n\n\ndef get_flow(provider_id: str, flow_id: str) -> OAuthFlow:\n    flow = _flows.get(flow_id)\n    if (\n        flow is not None\n        and flow.provider_id == provider_id\n        and (flow.server is None and flow.task is None and flow.persist_bundle is None)\n    ):\n        persisted = _load_persisted_oauth_flow(provider_id, flow_id)\n        if persisted is None:\n            _flows.pop(flow_id, None)\n            raise CodexAuthError(\"Authorization flow was not found or expired.\")\n        flow = persisted\n        _flows[flow.id] = flow\n    elif flow is None or flow.provider_id != provider_id:\n        flow = _load_persisted_oauth_flow(provider_id, flow_id)\n        if flow is None:\n            raise CodexAuthError(\"Authorization flow was not found or expired.\")\n        _flows[flow.id] = flow\n    if time.time() >= flow.expires_at and flow.status == \"pending\":\n        flow.status = \"error\"\n        flow.message = \"Authorization expired. Start a new connection.\"\n        if flow.task:\n            flow.task.cancel()\n        if flow.server:\n            flow.server.close()\n    return flow\n\n\nasync def complete_browser_flow(provider_id: str, flow_id: str, callback_url: str) -> OAuthFlow:","sourceCodeStart":570,"sourceCodeEnd":606,"githubUrl":"https://github.com/unslothai/unsloth/blob/203007d19051dcd2ae33876786d117c99f6b0368/studio/backend/core/inference/openai_codex_auth.py#L570-L606","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nflow = codex_auth.get_flow(provider_id, flow_id_from_yesterday)\n\n// after\ntry:\n    flow = codex_auth.get_flow(provider_id, flow_id_from_yesterday)\nexcept codex_auth.CodexAuthError:\n    flow = await codex_auth.start_browser_flow(provider_id, persist_bundle)  # mint a new flow","handlingStrategy":"validation","validationCode":"flow = None\ntry:\n    flow = codex_auth.get_flow(provider_id, flow_id)\nexcept codex_auth.CodexAuthError:\n    flow = None\nif flow is None:\n    flow = await start_new_flow(provider_id)  # never reuse an unresolvable flow_id","typeGuard":"def flow_exists(provider_id: str, flow_id: str) -> bool:\n    try:\n        codex_auth.get_flow(provider_id, flow_id)\n        return True\n    except codex_auth.CodexAuthError:\n        return False","tryCatchPattern":"try:\n    flow = codex_auth.get_flow(provider_id, flow_id)\nexcept codex_auth.CodexAuthError as exc:\n    if \"not found or expired\" in str(exc):\n        return RedirectResponse(\"/connect/chatgpt\")  # restart UX\n    raise","preventionTips":["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."],"tags":["oauth","flow-state","persistence","not-found","codex"],"backgroundTag":null,"analyzedSha":"203007d19051dcd2ae33876786d117c99f6b0368","analyzedAt":"2026-08-15T02:48:39.846Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}