{"record":{"id":"7ccc3b4951e99187","repo":"tinyhumansai/openhuman","slug":"session-expired-backend-session-not-active-sign-7ccc3b","errorCode":null,"errorMessage":"SESSION_EXPIRED: backend session not active — sign in to resume LLM work","messagePattern":"SESSION_EXPIRED: backend session not active — sign in to resume LLM work","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"src/openhuman/inference/provider/openhuman_backend_model.rs","lineNumber":114,"sourceCode":"        self.profile.streaming_tool_chunks = enabled;\n        self\n    }\n\n    fn state_dir(&self) -> PathBuf {\n        self.options.openhuman_dir.clone().unwrap_or_else(|| {\n            directories::UserDirs::new()\n                .map(|dirs| dirs.home_dir().join(\".openhuman\"))\n                .unwrap_or_else(|| PathBuf::from(\".openhuman\"))\n        })\n    }\n\n    fn resolve_bearer(&self) -> anyhow::Result<String> {\n        use crate::openhuman::security::credentials::session_support::{\n            classify_session_token, SessionTokenCheck,\n        };\n\n        if crate::openhuman::cron::scheduler_gate::is_signed_out() {\n            anyhow::bail!(\n                \"SESSION_EXPIRED: backend session not active — sign in to resume LLM work\"\n            );\n        }\n        let auth = AuthService::new(&self.state_dir(), self.options.secrets_encrypt);\n        let profile = auth.get_profile(\n            APP_SESSION_PROVIDER,\n            self.options.auth_profile_override.as_deref(),\n        )?;\n\n        // #5503: precheck the recorded JWT `exp` BEFORE building a request, the\n        // same way `require_live_session_token` guards the backend REST callers.\n        // Managed inference used to fire a doomed request on an expired-but-\n        // stored token and let the 401 come back — but an expired session can\n        // also surface upstream as a misleading \"model unavailable\", which is a\n        // core symptom of #5503 (all tiers \"die\" over a long session). Failing\n        // fast as `session_expired` routes the user to re-auth instead. Offline\n        // / local sessions (`is_local_session_token`) and `exp`-less tokens\n        // carry no recorded expiry, so `classify_session_token` returns `Live`","sourceCodeStart":96,"sourceCodeEnd":132,"githubUrl":"https://github.com/tinyhumansai/openhuman/blob/749120085864ce16e0f273c7b86fac7740b39c5b/src/openhuman/inference/provider/openhuman_backend_model.rs#L96-L132","documentation":"The managed OpenHuman backend model resolves its bearer token per request (`resolve_bearer`, openhuman_backend_model.rs). The fast path asks `cron::scheduler_gate::is_signed_out()`; if the session is known-dead, it bails with this `SESSION_EXPIRED` message so the caller routes to re-auth instead of firing a doomed HTTP request.","triggerScenarios":"Any managed-backend chat/embeddings call while the scheduler gate has marked the session signed out (logout, server-side 401 observed earlier, token revocation).","commonSituations":"Desktop left running overnight after the JWT was revoked; sign-out in one surface while another workload (chat turn, background embedding) fires; token invalidated by an account event.","solutions":["Sign in again — the next `resolve_bearer` call re-checks the gate after re-auth.","If it persists right after signing in, restart the core so the scheduler gate's signed-out flag is cleared.","Check connectivity: a gate that flipped due to transient 401s (captive portal, proxy) also recovers on restart/re-auth.","For headless setups, script re-auth or use a local provider to avoid the backend dependency."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"if crate::openhuman::cron::scheduler_gate::is_signed_out() {\n    return Err(anyhow::anyhow!(\"SESSION_EXPIRED\")); // preempt the managed-backend call\n}","typeGuard":null,"tryCatchPattern":"match model.chat(req).await {\n    Err(e) if e.to_string().starts_with(\"SESSION_EXPIRED\") => {\n        maybe_publish_local_session_expiry();\n        route_to_re_auth()\n    }\n    other => other,\n}","preventionTips":["Route all `SESSION_EXPIRED:`-prefixed errors to the re-auth flow uniformly.","Pause background managed-backend workloads on sign-out events.","Restart the core after re-auth if the gate's signed-out state appears sticky."],"tags":["session-expired","auth","managed-backend","inference"],"backgroundTag":"session-expired","analyzedSha":"749120085864ce16e0f273c7b86fac7740b39c5b","analyzedAt":"2026-08-17T21:21:45.363Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}