{"record":{"id":"81fda8fb7b8ca68f","repo":"Y2Z/monolith","slug":"invalid-user-agent-header-specified","errorCode":null,"errorMessage":"Invalid User-Agent header specified","messagePattern":"Invalid User-Agent header specified","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/session.rs","lineNumber":33,"sourceCode":"pub struct Session {\n    cache: Option<Cache>,\n    client: Client,\n    cookies: Option<Vec<Cookie>>,\n    pub options: MonolithOptions,\n    urls: Vec<String>,\n}\n\nimpl Session {\n    pub fn new(\n        cache: Option<Cache>,\n        cookies: Option<Vec<Cookie>>,\n        options: MonolithOptions,\n    ) -> Self {\n        let mut header_map = HeaderMap::new();\n        if let Some(user_agent) = &options.user_agent {\n            header_map.insert(\n                USER_AGENT,\n                HeaderValue::from_str(user_agent).expect(\"Invalid User-Agent header specified\"),\n            );\n        }\n        let client = Client::builder()\n            .timeout(Duration::from_secs(if options.timeout > 0 {\n                options.timeout\n            } else {\n                // We have to specify something that eventually makes the program fail\n                // (prevent it from hanging forever)\n                600 // 10 minutes in seconds\n            }))\n            .danger_accept_invalid_certs(options.insecure)\n            .default_headers(header_map)\n            .build()\n            .expect(\"Failed to initialize HTTP client\");\n\n        Session {\n            cache,\n            cookies,","sourceCodeStart":15,"sourceCodeEnd":51,"githubUrl":"https://github.com/Y2Z/monolith/blob/a6fc8d009514b2ea271dda2539f19a1f479ebfab/src/session.rs#L15-L51","documentation":"In `Session::new` (src/session.rs:33), when the caller supplies a `user_agent` in `MonolithOptions`, it is converted to a `HeaderValue` via `HeaderValue::from_str(user_agent).expect(\"Invalid User-Agent header specified\")`. `from_str` rejects any string containing non-visible-ASCII characters (bytes outside 0x20–0x7E, plus DEL/0x7F). If the user-agent string contains such bytes (e.g. non-ASCII text, control characters, embedded newlines), the expect panics during session construction, aborting the whole program before any request is made.","triggerScenarios":"Calling `Session::new` with `MonolithOptions.user_agent = Some(...)` where the value contains non-ASCII (Unicode) characters, control characters (e.g. \\n, \\r, \\t, \\0), or other bytes that violate HTTP header-value visibility rules. Via CLI: `monolith --user-agent \"…\" <url>` with a UA string pasted containing smart quotes, emoji, CJK text, or a stray newline from a shell variable.","commonSituations":"Pasting a UA string from a browser devtools export that includes non-ASCII characters; shell variables with trailing control characters or a newline; localized scripts that embed unicode text in the UA; config files read with wrong encoding (UTF-16/BOM bytes leaking in); programmatically constructing options from user input without sanitization.","solutions":["Pass only ASCII user-agent strings (visible characters, no newlines): e.g. use the standard browser UA format.","Sanitize/strip the value before constructing options: keep only bytes in 0x20–0x7E and trim whitespace.","If the goal is a Unicode-looking UA, percent-style or transliterate it — HTTP header values must be visible ASCII.","In wrapper scripts, validate the UA first: reject or filter it if it fails an ASCII-visible-charset check.","Patch the code to handle the Result gracefully (fall back to the default UA and warn) instead of expect()-panicking."],"exampleFix":"// before\noptions.user_agent = Some(\"Mønolith/1.0 🚀\\n\".to_string());\n// Session::new panics: Invalid User-Agent header specified\n\n// after\nlet ua: String = \"Mønolith/1.0 🚀\\n\"\n    .chars()\n    .filter(|c| (*c as u32) >= 0x20 && (*c as u32) <= 0x7E)\n    .collect();\noptions.user_agent = if ua.is_empty() {\n    None // falls back to default UA\n} else {\n    Some(ua)\n};","handlingStrategy":"validation","validationCode":"// Validate the user agent before building MonolithOptions\nfn is_valid_user_agent(ua: &str) -> bool {\n    !ua.is_empty()\n        && ua\n            .bytes()\n            .all(|b| (0x20..=0x7E).contains(&b))\n        && !ua.starts_with(' ')\n        && !ua.ends_with(' ')\n}\n\n// caller\nlet ua = cli.user_agent.unwrap_or_else(|| DEFAULT_USER_AGENT.to_string());\nassert!(is_valid_user_agent(&ua), \"user-agent must be visible ASCII\");\noptions.user_agent = Some(ua);","typeGuard":"fn is_safe_header_value(s: &str) -> bool {\n    s.bytes().all(|b| (0x20..=0x7E).contains(&b))\n}\n\n// usage\nif let Some(ua) = &options.user_agent {\n    if !is_safe_header_value(ua) {\n        eprintln!(\"ignoring invalid user-agent (must be visible ASCII)\");\n        options.user_agent = None; // fall back to default\n    }\n}","tryCatchPattern":"match HeaderValue::from_str(user_agent) {\n    Ok(v) => { header_map.insert(USER_AGENT, v); }\n    Err(_) => {\n        eprintln!(\"warning: invalid user-agent, using default\");\n        header_map.insert(USER_AGENT, HeaderValue::from_static(DEFAULT_USER_AGENT));\n    }\n}","preventionTips":["Only pass visible-ASCII user-agent strings (no unicode, emoji, or control characters).","Trim shell variables and strip newlines before assigning --user-agent.","Read UA values from config with correct encoding (avoid BOM/UTF-16 leakage).","Sanitize any user-supplied header value with an ASCII-visibility filter before constructing options.","Favor a graceful fallback to the default UA over expect() when patching the library."],"tags":["http","headers","panic","user-agent","validation"],"backgroundTag":"invalid-http-header-value","analyzedSha":"a6fc8d009514b2ea271dda2539f19a1f479ebfab","analyzedAt":"2026-09-05T20:13:04.517Z","contentChangedAt":"2026-09-05T20:13:04.517Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}