tinyhumansai/openhuman · error · anyhow::Error
SESSION_EXPIRED: backend session not active — sign in to res
Error message
SESSION_EXPIRED: backend session not active — sign in to resume LLM work
What it means
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.
Source
Thrown at src/openhuman/inference/provider/openhuman_backend_model.rs:114
self.profile.streaming_tool_chunks = enabled;
self
}
fn state_dir(&self) -> PathBuf {
self.options.openhuman_dir.clone().unwrap_or_else(|| {
directories::UserDirs::new()
.map(|dirs| dirs.home_dir().join(".openhuman"))
.unwrap_or_else(|| PathBuf::from(".openhuman"))
})
}
fn resolve_bearer(&self) -> anyhow::Result<String> {
use crate::openhuman::security::credentials::session_support::{
classify_session_token, SessionTokenCheck,
};
if crate::openhuman::cron::scheduler_gate::is_signed_out() {
anyhow::bail!(
"SESSION_EXPIRED: backend session not active — sign in to resume LLM work"
);
}
let auth = AuthService::new(&self.state_dir(), self.options.secrets_encrypt);
let profile = auth.get_profile(
APP_SESSION_PROVIDER,
self.options.auth_profile_override.as_deref(),
)?;
// #5503: precheck the recorded JWT `exp` BEFORE building a request, the
// same way `require_live_session_token` guards the backend REST callers.
// Managed inference used to fire a doomed request on an expired-but-
// stored token and let the 401 come back — but an expired session can
// also surface upstream as a misleading "model unavailable", which is a
// core symptom of #5503 (all tiers "die" over a long session). Failing
// fast as `session_expired` routes the user to re-auth instead. Offline
// / local sessions (`is_local_session_token`) and `exp`-less tokens
// carry no recorded expiry, so `classify_session_token` returns `Live`View on GitHub (pinned to 7491200858)
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.
Defensive patterns
Strategy: try-catch
Validate before calling
if crate::openhuman::cron::scheduler_gate::is_signed_out() {
return Err(anyhow::anyhow!("SESSION_EXPIRED")); // preempt the managed-backend call
} Try / catch
match model.chat(req).await {
Err(e) if e.to_string().starts_with("SESSION_EXPIRED") => {
maybe_publish_local_session_expiry();
route_to_re_auth()
}
other => other,
} Prevention
- 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.
When it happens
Trigger: Any managed-backend chat/embeddings call while the scheduler gate has marked the session signed out (logout, server-side 401 observed earlier, token revocation).
Common situations: 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.
Related errors
- SESSION_EXPIRED: backend session not active — sign in to use
- SESSION_EXPIRED: no backend session — sign in to use OpenHum
- SESSION_EXPIRED: backend session token expired locally — re-
- No backend session: store a JWT via auth (app-session)
- Model testing is only available in the desktop app.
AI-assisted analysis of tinyhumansai/openhuman@7491200858 (2026-08-17).
Data as JSON: /api/errors/7ccc3b4951e99187.
Report an issue: GitHub.