zeroclaw-labs/zeroclaw · critical

valid bearer token header

Error message

valid bearer token header

What it means

`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.

Source

Thrown at crates/zeroclaw-tools/src/linkedin_client.rs:172

            refresh_token,
            person_id,
        })
    }

    fn client() -> reqwest::Client {
        zeroclaw_config::schema::build_runtime_proxy_client_with_timeouts(
            "tool.linkedin",
            LINKEDIN_REQUEST_TIMEOUT_SECS,
            LINKEDIN_CONNECT_TIMEOUT_SECS,
        )
    }

    fn api_headers(&self, token: &str) -> HeaderMap {
        let mut headers = HeaderMap::new();
        let bearer = format!("Bearer {}", token);
        headers.insert(
            reqwest::header::AUTHORIZATION,
            HeaderValue::from_str(&bearer).expect("valid bearer token header"),
        );
        headers.insert(
            "LinkedIn-Version",
            HeaderValue::from_str(&self.api_version).expect("valid api version header"),
        );
        headers.insert(
            "X-Restli-Protocol-Version",
            HeaderValue::from_static("2.0.0"),
        );
        headers
    }

    async fn api_request(
        &self,
        method: Method,
        url: &str,
        token: &str,
        body: Option<serde_json::Value>,

View on GitHub (pinned to 88bb9c8533)

Solutions

  1. Trim the token where it is loaded: pass `token.trim()` into the client
  2. Fix the stored credential — remove quotes, whitespace, and newlines in the env var, auth store, or config entry
  3. Validate the token is header-safe ASCII before invoking the LinkedIn tool (see guard below)

Example fix

// before
let bearer = format!("Bearer {}", token); // token has a trailing newline
HeaderValue::from_str(&bearer).expect("valid bearer token header"),

// after
let bearer = format!("Bearer {}", token.trim());
HeaderValue::from_str(&bearer).expect("valid bearer token header"),
Defensive patterns

Strategy: validation

Validate before calling

fn ensure_header_safe(token: &str) -> Result<&str, String> {
    let t = token.trim();
    if t.is_empty() || !t.bytes().all(|b| (0x21..=0x7e).contains(&b)) {
        return Err("token contains non header-safe characters".into());
    }
    Ok(t)
}

Type guard

fn is_valid_bearer_token(token: &str) -> bool {
    let t = token.trim();
    !t.is_empty() && t.bytes().all(|b| (0x21..=0x7e).contains(&b))
}

Try / catch

// only when credentials are untrusted and panic=unwind is set:
let outcome = std::panic::catch_unwind(|| client.api_request(/* ... */));
if outcome.is_err() {
    // treat as a malformed credential: trim/replace the token and retry once
}

Prevention

When it happens

Trigger: 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.

Common situations: `$(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.

Related errors


AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23). Data as JSON: /api/errors/7ff0bcc2b84c0fca. Report an issue: GitHub.