{"record":{"id":"7f9e0cb2fdc0eb91","repo":"Kuberwastaken/claurst","slug":"poll-no-token","errorCode":null,"errorMessage":"Poll: no token","messagePattern":"Poll: no token","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src-rust/crates/bridge/src/lib.rs","lineNumber":550,"sourceCode":"    }\r\n\r\n    // -----------------------------------------------------------------------\r\n    // Polling\r\n    // -----------------------------------------------------------------------\r\n\r\n    /// Long-poll for incoming messages from the web UI.\r\n    ///\r\n    /// GET `/api/claude_code/sessions/{id}/poll`\r\n    ///\r\n    /// - `200` → JSON array of [`BridgeMessage`]; may be empty.\r\n    /// - `204` → No messages; returns empty vec.\r\n    /// - `401`/`403` → Auth failure; sets state to `Disconnected` and errors.\r\n    async fn poll_messages(&self) -> anyhow::Result<Vec<BridgeMessage>> {\r\n        let token = self\r\n            .config\r\n            .session_token\r\n            .as_deref()\r\n            .ok_or_else(|| anyhow::anyhow!(\"Poll: no token\"))?;\r\n\r\n        let url = format!(\r\n            \"{}/api/claude_code/sessions/{}/poll\",\r\n            self.config.server_url, self.session_id\r\n        );\r\n\r\n        let resp = self\r\n            .http\r\n            .get(&url)\r\n            .bearer_auth(token)\r\n            .timeout(std::time::Duration::from_secs(35))\r\n            .send()\r\n            .await\r\n            .context(\"Bridge poll: HTTP send failed\")?;\r\n\r\n        let status = resp.status().as_u16();\r\n        match status {\r\n            200 => {\r","sourceCodeStart":532,"sourceCodeEnd":568,"githubUrl":"https://github.com/Kuberwastaken/claurst/blob/b0637c97ec34144387cbf2f74f65df6d16a6cef1/src-rust/crates/bridge/src/lib.rs#L532-L568","documentation":"`poll_messages` fetches new Remote Control messages from the server and requires the session token for the Authorization header. If `config.session_token` is `None` at poll time, the call fails with this error instead of issuing an unauthenticated request. Unlike registration, this can occur mid-session if the token was somehow cleared after registration.","triggerScenarios":"`poll_messages` (invoked from `run_poll_loop`) executed while `self.config.session_token` is `None` — typically a bridge built without a token, or a config mutated after startup.","commonSituations":"Reusing a bridge instance whose config was rebuilt without the token; tests constructing a bare BridgeConfig; a long-running loop after the token was removed from config.","solutions":["Ensure the token is present before starting the poll loop — bail early at startup (the start path already validates this).","If the token can rotate, store it in an `Arc<RwLock<Option<String>>>` and refresh rather than setting it to None.","Restart the bridge via the normal start path so the token is resolved from CLAURST_BRIDGE_TOKEN."],"exampleFix":"// before\nif bridge.config.session_token.is_none() {\n    bridge.run_poll_loop().await?; // Poll: no token\n}\n// after\nif bridge.config.session_token.is_none() {\n    anyhow::bail!(\"Cannot start poll loop without a session token\");\n}\nbridge.run_poll_loop().await?;","handlingStrategy":"validation","validationCode":"// Guard the poll loop entry\nassert!(bridge.config.session_token.is_some(), \"poll requires a session token\");","typeGuard":null,"tryCatchPattern":"match bridge.poll_messages().await {\n    Err(e) if e.to_string().contains(\"no token\") => {\n        // stop the loop and surface a config error instead of spinning\n        state.set(Disconnected);\n        return Err(e);\n    }\n    other => other,\n}","preventionTips":["Validate the token once at startup and pass it through the loop, never re-reading possibly-cleared config.","Keep the token immutable for the bridge's lifetime (Arc<str>) to prevent accidental clearing.","Stop the poll loop on auth errors instead of retrying without credentials."],"tags":["bridge","authentication","remote-control","missing-token"],"backgroundTag":"missing-credentials","analyzedSha":"b0637c97ec34144387cbf2f74f65df6d16a6cef1","analyzedAt":"2026-09-10T00:24:58.650Z","contentChangedAt":"2026-09-10T00:24:58.650Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}