{"record":{"id":"760a41b45bbacce4","repo":"zeroclaw-labs/zeroclaw","slug":"url-cannot-contain-whitespace-760a41","errorCode":null,"errorMessage":"URL cannot contain whitespace","messagePattern":"URL cannot contain whitespace","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/zeroclaw-tools/src/http_request.rs","lineNumber":127,"sourceCode":"            config_path: Some(config_path),\n            secrets_encrypt,\n        })\n    }\n\n    #[cfg(test)]\n    fn validate_url(&self, raw_url: &str) -> anyhow::Result<String> {\n        Ok(self.validate_url_policy(raw_url)?.url)\n    }\n\n    fn validate_url_policy(&self, raw_url: &str) -> anyhow::Result<HttpRequestUrlPolicy> {\n        let url = raw_url.trim();\n\n        if url.is_empty() {\n            anyhow::bail!(\"URL cannot be empty\");\n        }\n\n        if url.chars().any(char::is_whitespace) {\n            anyhow::bail!(\"URL cannot contain whitespace\");\n        }\n\n        if !url.starts_with(\"http://\") && !url.starts_with(\"https://\") {\n            anyhow::bail!(\"Only http:// and https:// URLs are allowed\");\n        }\n\n        if self.allowed_domains.is_empty() {\n            anyhow::bail!(\n                \"HTTP request tool is enabled but no allowed_domains are configured. Add [http_request].allowed_domains in config.toml\"\n            );\n        }\n\n        let host = extract_host(url)?;\n        if let Ok(ip) = host.parse::<IpAddr>() {\n            if domain_guard::is_known_cloud_metadata_endpoint(ip) {\n                anyhow::bail!(\"Blocked cloud metadata host: {host}\");\n            }\n            if domain_guard::is_cloud_metadata_ip(ip) {","sourceCodeStart":109,"sourceCodeEnd":145,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-tools/src/http_request.rs#L109-L145","documentation":"Thrown by HttpRequestTool::validate_url_policy (crates/zeroclaw-tools/src/http_request.rs:127) when the URL, after leading/trailing trimming, still contains any whitespace character (space, tab, newline) anywhere in it. The http_request tool rejects such URLs before scheme or allowlist checks because unencoded whitespace is invalid in an HTTP request target and can be used to smuggle or corrupt headers. It is a fail-closed input-validation error, not a network error.","triggerScenarios":"Calling tool.execute with args.url = \"https://example.com/hello world\" (unencoded space in the path); a URL pasted from a terminal that contains a tab or a line-wrap newline; building the URL by string concatenation where one variable carries interior whitespace. Leading/trailing whitespace alone does NOT trigger it because the URL is trimmed first; only interior whitespace does.","commonSituations":"LLM/agent-generated URLs containing natural-language fragments; URLs copied from documentation that wrapped across lines; query strings assembled with raw spaces instead of percent-encoding; templating code that interpolates unvalidated user input into the path or query.","solutions":["Percent-encode every space and control character in the path/query before calling the tool (space -> %20, tab -> %09, newline -> %0A).","Trim the URL and assert it has no interior whitespace before invoking http_request.","Build URLs with a URL encoder (e.g. url::Url with query_pairs_mut, or urlencoding::encode) instead of raw string concatenation."],"exampleFix":"// before\nlet args = json!({\"url\": \"https://example.com/hello world\"});\ntool.execute(args).await?; // -> URL cannot contain whitespace\n\n// after\nlet args = json!({\"url\": \"https://example.com/hello%20world\"});\ntool.execute(args).await?;","handlingStrategy":"validation","validationCode":"fn url_is_clean(url: &str) -> bool {\n    let t = url.trim();\n    !t.is_empty() && !t.chars().any(char::is_whitespace)\n}","typeGuard":"fn has_interior_whitespace(url: &str) -> bool {\n    url.trim().chars().any(char::is_whitespace)\n}","tryCatchPattern":"let result = tool.execute(args).await?;\nif let Some(err) = &result.error {\n    if err.contains(\"URL cannot contain whitespace\") {\n        // percent-encode the URL and retry once with sanitized input\n    }\n}","preventionTips":["Always build URLs with a URL encoder; never interpolate raw strings into the path or query.","Trim and whitespace-check URLs at the boundary where user/model input enters your system.","Reject or encode tabs/newlines early; they are almost always injection artifacts."],"tags":["http","url","whitespace","validation","zeroclaw"],"backgroundTag":"invalid-url-format","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}