{"record":{"id":"e7edc30693327264","repo":"tinyhumansai/openhuman","slug":"backend-rejected-session-token-on-method-path","errorCode":null,"errorMessage":"backend rejected session token on {method} {path}","messagePattern":"backend rejected session token on (.+?) (.+?)","errorType":"http","errorClass":"BackendApiError::Unauthorized","httpStatus":401,"severity":"error","filePath":"src/api/rest.rs","lineNumber":669,"sourceCode":"            // code bug — every authed endpoint will see this once the session\n            // lapses. Surface a typed `BackendApiError::Unauthorized` so the\n            // auth domain can drive recovery, and skip `report_error` to\n            // avoid Sentry noise. Targets `OPENHUMAN-TAURI-4K8` (mascot TTS\n            // surfaced it first on `/openai/v1/audio/speech`, but the same\n            // shape applies to every `authed_json` path).\n            if status_code == 401 {\n                tracing::info!(\n                    domain = \"backend_api\",\n                    operation = \"authed_json\",\n                    method = method.as_str(),\n                    path = url.path(),\n                    status = status_code,\n                    failure = \"non_2xx\",\n                    \"[backend_api] 401 on {} {} — session token rejected, surfacing typed error\",\n                    method.as_str(),\n                    url.path(),\n                );\n                return Err(anyhow::Error::new(BackendApiError::Unauthorized {\n                    method: method.as_str().to_string(),\n                    path: url.path().to_string(),\n                }));\n            }\n\n            // 404 on `/channels/<provider>/messages/<id>` is an expected\n            // state (user deleted the message provider-side, or backend\n            // GC'd the relay row) — not a code bug. Surface a typed\n            // `BackendApiError::MessageNotFound` so callers (`bus.rs`\n            // streaming/thinking/delete/final paths) can clear stale\n            // ids and skip retry, without funneling the 404 into\n            // `report_error`. Targets `OPENHUMAN-TAURI-2Y` (~454 events).\n            if status_code == 404 {\n                let channel_message = parse_message_path(url.path());\n                // A 404 on the *edit* route is normally route absence, not\n                // message absence — today the backend implements no `PATCH\n                // /channels/:channel/messages/:messageId` at all (#5230). Answer\n                // with a distinct typed error so `bus.rs` keeps the message id","sourceCodeStart":651,"sourceCodeEnd":687,"githubUrl":"https://github.com/tinyhumansai/openhuman/blob/749120085864ce16e0f273c7b86fac7740b39c5b/src/api/rest.rs#L651-L687","documentation":"authed_json maps a backend 401 to the typed BackendApiError::Unauthorized: the session token was rejected (expired or revoked). It is an expected session-lapse signal for the auth domain to drive re-login, deliberately kept out of Sentry reporting; every authed endpoint sees it once the session lapses.","triggerScenarios":"Thrown at src/api/rest.rs:669 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Refresh the session token or re-authenticate the user","Handle BackendApiError::Unauthorized at the call site by routing to login/recovery instead of retrying with the stale token"],"exampleFix":null,"handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"749120085864ce16e0f273c7b86fac7740b39c5b","analyzedAt":"2026-08-17T21:21:45.363Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}