{"record":{"id":"c795a415a0ac9584","repo":"t8y2/dbx","slug":"invalid-tdengine-host","errorCode":null,"errorMessage":"invalid TDengine host","messagePattern":"invalid TDengine host","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"agents/drivers/tdengine/src/config.rs","lineNumber":55,"sourceCode":"        set_query_param(&mut url, \"tls_ca\", params.ca_cert_path.trim());\n    }\n    let database = url\n        .path_segments()\n        .and_then(|mut segments| segments.find(|segment| !segment.is_empty()))\n        .map(|segment| percent_decode_str(segment).decode_utf8_lossy().into_owned())\n        .unwrap_or_default();\n    Ok(BuiltDsn { value: url.into(), database })\n}\n\nfn build_from_fields(params: &ConnectParams) -> Result<Url> {\n    let scheme = if params.ssl { \"wss\" } else { \"ws\" };\n    let host = if params.host.trim().is_empty() { DEFAULT_HOST } else { params.host.trim() };\n    let port = if params.port == 0 { DEFAULT_PORT } else { params.port };\n    let username = if params.username.is_empty() { DEFAULT_USER } else { &params.username };\n    let password = if params.password.is_empty() { DEFAULT_PASSWORD } else { &params.password };\n    let mut url = Url::parse(&format!(\"{scheme}://{DEFAULT_HOST}:{port}/\"))?;\n    if let Ok(address) = host.parse::<IpAddr>() {\n        url.set_ip_host(address).map_err(|_| anyhow::anyhow!(\"invalid TDengine host\"))?;\n    } else {\n        url.set_host(Some(host)).map_err(|_| anyhow::anyhow!(\"invalid TDengine host\"))?;\n    }\n    url.set_username(username).map_err(|_| anyhow::anyhow!(\"invalid TDengine username\"))?;\n    url.set_password(Some(password)).map_err(|_| anyhow::anyhow!(\"invalid TDengine password\"))?;\n    if !params.database.trim().is_empty() {\n        url.set_path(&format!(\"/{}\", params.database.trim()));\n    }\n    Ok(url)\n}\n\nfn apply_connection_fields(url: &mut Url, params: &ConnectParams) -> Result<()> {\n    if url.username().is_empty() {\n        let username = if params.username.is_empty() { DEFAULT_USER } else { &params.username };\n        url.set_username(username).map_err(|_| anyhow::anyhow!(\"invalid TDengine username\"))?;\n    }\n    if url.password().is_none() {\n        let password = if params.password.is_empty() { DEFAULT_PASSWORD } else { &params.password };","sourceCodeStart":37,"sourceCodeEnd":73,"githubUrl":"https://github.com/t8y2/dbx/blob/c0390bff16418b651f4728520d99adf8ce48829a/agents/drivers/tdengine/src/config.rs#L37-L73","documentation":"Thrown in `build_from_fields` when the trimmed host value cannot be installed into the URL: if it parses as an IP address, `set_ip_host` failed; otherwise `set_host(Some(host))` rejected it as not a valid host per RFC 3986. Defaults (DEFAULT_HOST) are used only for empty input, so a non-empty but malformed host reaches Url and fails there.","triggerScenarios":"Passing a host string containing spaces, underscores in invalid positions, a scheme/protocol prefix like \"http://host\", userinfo, a path (\"host/db\"), or an invalid IPv6 literal (not bracketed correctly); also an IP literal that url::set_ip_host rejects.","commonSituations":"Pasting \"http://localhost:6041\" into a host-only config field; copying \"host:port\" including the port into the host field; trailing slashes or paths in the host; environment variables with stray whitespace/quotes from shell interpolation; IPv6 addresses written without brackets.","solutions":["Set host to a bare hostname or IP only: no scheme, no port, no path (use the port field for the port).","Strip scheme prefixes and paths: convert \"http://host:6041\" to host=\"host\", port=6041.","For IPv6, pass the address so set_ip_host accepts it (or use the standard bracketed form the parser expects).","Trim whitespace/quotes from the host env var or config value before constructing params."],"exampleFix":"// before\nlet params = ConnectionParams { host: \"http://tdengine:6041\".into(), .. };\n// after\nlet params = ConnectionParams { host: \"tdengine\".into(), port: 6041, .. };","handlingStrategy":"validation","validationCode":"fn validate_host(host: &str) -> Result<(), String> {\n    let h = host.trim();\n    if h.is_empty() {\n        return Ok(()); // falls back to DEFAULT_HOST\n    }\n    if h.contains(\"://\") || h.contains('/') || h.contains('@') || h.contains(' ') {\n        return Err(format!(\"host must be a bare hostname or IP, got: {h}\"));\n    }\n    if h.parse::<std::net::IpAddr>().is_ok() || h.parse::<std::net::ToSocketAddrs>().is_ok() {\n        Ok(())\n    } else {\n        Err(format!(\"invalid TDengine host: {h}\"))\n    }\n}","typeGuard":"fn is_bare_host(s: &str) -> bool {\n    let h = s.trim();\n    !h.is_empty()\n        && !h.contains(\"://\")\n        && !h.contains('/')\n        && !h.contains('@')\n        && (h.parse::<std::net::IpAddr>().is_ok()\n            || h.split('.').count() > 1\n            || h == \"localhost\")\n}","tryCatchPattern":null,"preventionTips":["Keep host and port in separate config fields; never embed the port or scheme in host.","Strip any \"http://\" or \"https://\" prefix when importing configs from other tools.","Trim whitespace and shell quotes from host env vars.","Write IPv6 addresses in bracketed/valid form and test the DSN at startup."],"tags":["config","url","host","tdengine"],"backgroundTag":"invalid-hostname","analyzedSha":"c0390bff16418b651f4728520d99adf8ce48829a","analyzedAt":"2026-09-05T23:05:10.900Z","contentChangedAt":"2026-09-05T23:05:10.900Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}