tinyhumansai/openhuman · error · anyhow::Error
No backend session: store a JWT via auth (app-session)
Error message
No backend session: store a JWT via auth (app-session)
What it means
The managed-backend model found no stored app-session JWT at all: `classify_session_token` returned `Absent` because `auth.get_profile(APP_SESSION_PROVIDER, ...)` yielded no profile/token (openhuman_backend_model.rs:~144). Unlike the Expired case there is nothing to check or refresh — the credential was never stored or was lost.
Source
Thrown at src/openhuman/inference/provider/openhuman_backend_model.rs:144
// 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`
// for them — their behaviour is unchanged and the post-call 401 net
// still covers a server-side revocation.
match classify_session_token(profile.as_ref(), chrono::Utc::now()) {
SessionTokenCheck::Live(token) => Ok(token),
SessionTokenCheck::Expired => {
maybe_publish_local_session_expiry();
anyhow::bail!(
"SESSION_EXPIRED: backend session token expired locally — re-authentication required"
)
}
SessionTokenCheck::Absent => {
anyhow::bail!("No backend session: store a JWT via auth (app-session)")
}
}
}
fn base_url(&self) -> String {
format!(
"{}/openai/v1",
effective_api_url(&self.api_url).trim_end_matches('/')
)
}
/// Resolve the current JWT + base URL and build a fresh crate `OpenAiModel`
/// (Bearer). Rebuilt per call because the session JWT rotates.
fn build_wire_model(&self) -> TaResult<OpenAiModel> {
let token = self
.resolve_bearer()
.map_err(|e| TinyAgentsError::Model(e.to_string()))?;
let base_url = self.base_url();View on GitHub (pinned to 7491200858)
Solutions
- Complete the sign-in flow so an app-session JWT is stored, then retry.
- If using `auth_profile_override`, verify that profile id exists in the auth store.
- Confirm the state dir (`~/.openhuman` or the config parent) is the one your sign-in wrote to.
- For pre-auth onboarding steps, gate them on auth completion or use a local provider.
Defensive patterns
Strategy: validation
Validate before calling
let profile = auth.get_profile(APP_SESSION_PROVIDER, override_profile.as_deref())?;
if profile.is_none() {
return prompt_sign_in(); // no stored JWT — the managed call cannot succeed
} Type guard
fn has_app_session(auth: &AuthService, override_id: Option<&str>) -> bool {
auth.get_profile(APP_SESSION_PROVIDER, override_id)
.ok()
.flatten()
.is_some()
} Prevention
- Complete sign-in before any workload selects the managed backend.
- If using auth_profile_override, validate the profile id exists.
- Gate onboarding inference steps on auth completion or use a local provider.
When it happens
Trigger: Calling a managed-backend model before any sign-in completed; the auth-profiles store under the state dir has no APP_SESSION_PROVIDER entry (fresh install, workspace reset, `auth_profile_override` pointing at a non-existent profile).
Common situations: Onboarding flows that fire an inference call before auth finishes; `auth_profile_override` set to a profile id that doesn't exist; state dir mismatch after migration so the profile lookup reads the wrong store.
Related errors
- SESSION_EXPIRED: no backend session — sign in to use OpenHum
- SESSION_EXPIRED: backend session not active — sign in to res
- Failed to send magic link (${response.status})
- Request timed out. Please try again.
- Login token invalid or expired
AI-assisted analysis of tinyhumansai/openhuman@7491200858 (2026-08-17).
Data as JSON: /api/errors/40e154f9a3321a27.
Report an issue: GitHub.