{"record":{"id":"2252b0762a6959b8","repo":"windmill-labs/windmill","slug":"header-creation","errorCode":null,"errorMessage":"header creation","messagePattern":"header creation","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"backend/windmill-api-client/src/lib.rs","lineNumber":176,"sourceCode":"    /// List workspaces\n    pub async fn list_workspaces(&self) -> Result<Vec<types::Workspace>, Error> {\n        let url = format!(\"{}/workspaces/list\", self.baseurl);\n        let response = self.client.get(&url).send().await?;\n\n        if response.status().is_success() {\n            Ok(response.json().await?)\n        } else {\n            Err(Error::UnexpectedResponse(\n                response.status().as_u16(),\n                response.text().await.unwrap_or_default(),\n            ))\n        }\n    }\n}\n\n/// Create a client with bearer token authentication\npub fn create_client(base_url: &str, token: String) -> Client {\n    let mut val = HeaderValue::from_str(&format!(\"Bearer {token}\")).expect(\"header creation\");\n    val.set_sensitive(true);\n    let mut headers = HeaderMap::new();\n    headers.insert(AUTHORIZATION, val);\n    let client = reqwest::ClientBuilder::new()\n        .default_headers(headers)\n        .build()\n        .expect(\"client build\");\n    Client::new_with_client(&format!(\"{}/api\", base_url.trim_end_matches('/')), client)\n}\n\n/// Error type for API client\n#[derive(Debug)]\npub enum Error {\n    /// Request error\n    Request(reqwest::Error),\n    /// Unexpected response status\n    UnexpectedResponse(u16, String),\n}","sourceCodeStart":158,"sourceCodeEnd":194,"githubUrl":"https://github.com/windmill-labs/windmill/blob/e474e8803ce2ff5c2df09a58dab51d45f5c922ca/backend/windmill-api-client/src/lib.rs#L158-L194","documentation":"create_client builds a Bearer Authorization header from the given token via HeaderValue::from_str and unwraps it with expect(\"header creation\"). HeaderValue::from_str fails when the formatted string contains bytes that are not visible ASCII (0x20-0x7E) — e.g. control characters, newlines, or non-ASCII. A token read from env/config that contains a trailing newline or stray whitespace/control byte panics here.","triggerScenarios":"Calling create_client(base_url, token) where format!(\"Bearer {token}\") yields invalid header bytes: a token containing \\n or \\r (common when read from a file/env without trimming), non-ASCII characters, or control characters.","commonSituations":"Token loaded from a file that ends with a newline (e.g. `cat token.txt` or fs::read_to_string without trim); secrets managers returning values with trailing whitespace; copy-pasted tokens containing invisible characters; misconfigured env var holding a multiline value.","solutions":["Trim the token before passing it in: token.trim().to_string() in the caller (or inside create_client before formatting).","Validate the token is ASCII and printable before calling create_client (e.g. token.bytes().all(|b| b.is_ascii_graphic())).","Fix the source of the token: trim when reading from file/env, or correct the secret in the secrets manager.","If you control the library, replace .expect with proper error propagation (return Result<Client, Error>) so a bad token yields a descriptive error instead of a panic."],"exampleFix":"// before\nlet client = create_client(url, std::fs::read_to_string(\"token\")?);\n\n// after\nlet token = std::fs::read_to_string(\"token\")?.trim().to_string();\nlet client = create_client(url, token);","handlingStrategy":"validation","validationCode":"fn valid_token(token: &str) -> bool {\n    token.bytes().all(|b| b.is_ascii_graphic()) && !token.is_empty()\n}\n// call: if !valid_token(&token) { bail!(\"token contains invalid header characters\"); }","typeGuard":"fn sanitize_header_token(raw: &str) -> Option<String> {\n    let t = raw.trim();\n    (!t.is_empty() && t.bytes().all(|b| (0x21..=0x7e).contains(&b))).then(|| t.to_string())\n}","tryCatchPattern":null,"preventionTips":["Always .trim() tokens read from files or environment variables before passing to create_client.","Validate tokens are printable ASCII at the configuration-loading boundary.","Prefer library APIs returning Result over expect/unwrap when wrapping secret material into headers."],"tags":["rust","panic","http-headers","authentication"],"backgroundTag":"invalid-http-header-value","analyzedSha":"e474e8803ce2ff5c2df09a58dab51d45f5c922ca","analyzedAt":"2026-09-03T12:38:19.024Z","contentChangedAt":"2026-09-03T12:38:19.024Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}