{"record":{"id":"87d00315d325fc80","repo":"tinyhumansai/openhuman","slug":"session-expired-no-backend-session-sign-in-to-u","errorCode":null,"errorMessage":"SESSION_EXPIRED: no backend session — sign in to use OpenHuman","messagePattern":"SESSION_EXPIRED: no backend session — sign in to use OpenHuman","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"src/openhuman/inference/provider/factory.rs","lineNumber":1915,"sourceCode":"    let state_dir = config\n        .config_path\n        .parent()\n        .map(std::path::PathBuf::from)\n        .unwrap_or_else(|| {\n            directories::UserDirs::new()\n                .map(|d| d.home_dir().join(\".openhuman\"))\n                .unwrap_or_else(|| std::path::PathBuf::from(\".openhuman\"))\n        });\n    let auth = AuthService::new(&state_dir, config.secrets.encrypt);\n    let has_session = auth\n        .get_provider_bearer_token(\n            crate::openhuman::security::credentials::APP_SESSION_PROVIDER,\n            None,\n        )?\n        .filter(|s| !s.trim().is_empty())\n        .is_some();\n    if !has_session {\n        anyhow::bail!(\"SESSION_EXPIRED: no backend session — sign in to use OpenHuman\")\n    }\n    Ok(())\n}\n\nfn resolve_primary_cloud_provider_string(config: &Config) -> String {\n    let primary = config\n        .primary_cloud\n        .as_deref()\n        .and_then(|id| config.cloud_providers.iter().find(|entry| entry.id == id));\n\n    if primary.is_some_and(is_openhuman_cloud_entry) {\n        if let Some(legacy) = legacy_custom_inference_provider_string(config) {\n            return legacy;\n        }\n        // Primary is explicitly OpenHuman but inference_url points at a custom\n        // endpoint with no matching provider entry — this is a half-migrated BYOK\n        // config. Fail closed so the user sees an actionable error rather than\n        // silently routing through the managed backend.","sourceCodeStart":1897,"sourceCodeEnd":1933,"githubUrl":"https://github.com/tinyhumansai/openhuman/blob/749120085864ce16e0f273c7b86fac7740b39c5b/src/openhuman/inference/provider/factory.rs#L1897-L1933","documentation":"The custom-provider session gate passed the fast path (not marked signed out) but found no usable app-session JWT: `AuthService::get_provider_bearer_token(APP_SESSION_PROVIDER)` returned nothing or blank (factory.rs:~1908-1915). The credential store simply has no stored backend session token, so the `SESSION_EXPIRED` bail fires.","triggerScenarios":"First use of a custom provider before ever signing in; the auth-profiles store lost the app-session entry (corrupted store, workspace reset, fresh `~/.openhuman` state dir); sign-in recorded in a different user/workspace than the one the core reads.","commonSituations":"Fresh installs where the user skipped sign-in and configured a BYOK key directly; workspace switched (state_dir resolves elsewhere); migrated machines where the credentials store did not come along.","solutions":["Complete sign-in once so an app-session JWT is stored for APP_SESSION_PROVIDER, then retry.","If you believe you are signed in, verify the core's state dir matches the one auth wrote to (check `config.config_path` parent vs `~/.openhuman`).","For AgentBox/automation deployments, confirm `agentbox_mode_enabled()` is on — that mode intentionally bypasses this gate.","Re-authenticate after a workspace reset or profile migration."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"let has_session = AuthService::new(&state_dir, config.secrets.encrypt)\n    .get_provider_bearer_token(APP_SESSION_PROVIDER, None)?\n    .map(|t| !t.trim().is_empty())\n    .unwrap_or(false);\nif !has_session { return prompt_sign_in(); }","typeGuard":null,"tryCatchPattern":"match gate(&config) {\n    Err(e) if e.to_string().contains(\"no backend session\") => prompt_sign_in(),\n    other => other,\n}","preventionTips":["Gate first-use of custom providers behind a completed sign-in.","Ensure the core and the auth flow use the same state dir after migrations.","Prefer local providers for setups that will never sign in."],"tags":["session-expired","auth","missing-token","credentials"],"backgroundTag":"missing-auth-token","analyzedSha":"749120085864ce16e0f273c7b86fac7740b39c5b","analyzedAt":"2026-08-17T21:21:45.363Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}