{"record":{"id":"7ff0bcc2b84c0fca","repo":"zeroclaw-labs/zeroclaw","slug":"valid-bearer-token-header","errorCode":null,"errorMessage":"valid bearer token header","messagePattern":"valid bearer token header","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"crates/zeroclaw-tools/src/linkedin_client.rs","lineNumber":172,"sourceCode":"            refresh_token,\n            person_id,\n        })\n    }\n\n    fn client() -> reqwest::Client {\n        zeroclaw_config::schema::build_runtime_proxy_client_with_timeouts(\n            \"tool.linkedin\",\n            LINKEDIN_REQUEST_TIMEOUT_SECS,\n            LINKEDIN_CONNECT_TIMEOUT_SECS,\n        )\n    }\n\n    fn api_headers(&self, token: &str) -> HeaderMap {\n        let mut headers = HeaderMap::new();\n        let bearer = format!(\"Bearer {}\", token);\n        headers.insert(\n            reqwest::header::AUTHORIZATION,\n            HeaderValue::from_str(&bearer).expect(\"valid bearer token header\"),\n        );\n        headers.insert(\n            \"LinkedIn-Version\",\n            HeaderValue::from_str(&self.api_version).expect(\"valid api version header\"),\n        );\n        headers.insert(\n            \"X-Restli-Protocol-Version\",\n            HeaderValue::from_static(\"2.0.0\"),\n        );\n        headers\n    }\n\n    async fn api_request(\n        &self,\n        method: Method,\n        url: &str,\n        token: &str,\n        body: Option<serde_json::Value>,","sourceCodeStart":154,"sourceCodeEnd":190,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-tools/src/linkedin_client.rs#L154-L190","documentation":"`api_headers` formats `Bearer {token}` into an HTTP header value. `HeaderValue::from_str` rejects any byte outside visible ASCII (0x21-0x7E plus space and tab) — newlines, control characters, non-ASCII. The `.expect()` assumes the stored LinkedIn token is header-safe, so a token containing whitespace, quotes, or a trailing newline aborts the process before a request is sent.","triggerScenarios":"Any LinkedIn API call that builds headers (`api_request`, `api_headers`) with a token containing invalid header bytes: a trailing `\\n` from a file read, surrounding quotes from a paste, or a non-ASCII character inside the token string.","commonSituations":"`$(cat token.txt)` shell capture appending a newline; `.env` values pasted with quotes; secrets-manager entries with trailing whitespace; tokens copied from a web UI with zero-width characters.","solutions":["Trim the token where it is loaded: pass `token.trim()` into the client","Fix the stored credential — remove quotes, whitespace, and newlines in the env var, auth store, or config entry","Validate the token is header-safe ASCII before invoking the LinkedIn tool (see guard below)"],"exampleFix":"// before\nlet bearer = format!(\"Bearer {}\", token); // token has a trailing newline\nHeaderValue::from_str(&bearer).expect(\"valid bearer token header\"),\n\n// after\nlet bearer = format!(\"Bearer {}\", token.trim());\nHeaderValue::from_str(&bearer).expect(\"valid bearer token header\"),","handlingStrategy":"validation","validationCode":"fn ensure_header_safe(token: &str) -> Result<&str, String> {\n    let t = token.trim();\n    if t.is_empty() || !t.bytes().all(|b| (0x21..=0x7e).contains(&b)) {\n        return Err(\"token contains non header-safe characters\".into());\n    }\n    Ok(t)\n}","typeGuard":"fn is_valid_bearer_token(token: &str) -> bool {\n    let t = token.trim();\n    !t.is_empty() && t.bytes().all(|b| (0x21..=0x7e).contains(&b))\n}","tryCatchPattern":"// only when credentials are untrusted and panic=unwind is set:\nlet outcome = std::panic::catch_unwind(|| client.api_request(/* ... */));\nif outcome.is_err() {\n    // treat as a malformed credential: trim/replace the token and retry once\n}","preventionTips":["Trim tokens when reading them from env vars, files, or secrets managers","Never store tokens with surrounding quotes or whitespace","Add a startup auth check that validates credential shape before serving traffic"],"tags":["rust","http-headers","linkedin","panic","access-token"],"backgroundTag":"invalid-http-header-value","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}