{"record":{"id":"0cf4b9f145f63b01","repo":"xai-org/grok-build","slug":"invalid-tls-server-name-server-name-e","errorCode":null,"errorMessage":"Invalid TLS server name '{server_name}': {e}","messagePattern":"Invalid TLS server name '(.+?)': (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/codegen/xai-grok-shell/src/agent/proxy.rs","lineNumber":206,"sourceCode":"    if !remaining.is_empty() {\n        anyhow::bail!(\n            \"Proxy sent {} unexpected byte(s) after CONNECT response headers\",\n            remaining.len()\n        );\n    }\n\n    // 6. Reunite the split halves back into a TcpStream.\n    let stream = reader.into_inner().reunite(writer_half)?;\n    Ok(stream)\n}\n\nasync fn tls_wrap(\n    stream: TcpStream,\n    server_name: &str,\n) -> anyhow::Result<tokio_rustls::client::TlsStream<TcpStream>> {\n    let connector = tokio_rustls::TlsConnector::from(xai_grok_extra_ca::rustls_client_config());\n    let dns_name = rustls::pki_types::ServerName::try_from(server_name.to_string())\n        .map_err(|e| anyhow::anyhow!(\"Invalid TLS server name '{server_name}': {e}\"))?;\n\n    let tls_stream = connector\n        .connect(dns_name, stream)\n        .await\n        .map_err(|e| anyhow::anyhow!(\"TLS handshake through proxy failed: {e}\"))?;\n\n    Ok(tls_stream)\n}\n\n/// Parse a proxy URL into (host, port).\n///\n/// Accepted formats:\n/// - `http://host:port`\n/// - `http://host` (defaults to port 80)\n/// - `host:port`\nfn parse_proxy_url(url: &str) -> anyhow::Result<(String, u16)> {\n    // Strip scheme if present.\n    let without_scheme = url","sourceCodeStart":188,"sourceCodeEnd":224,"githubUrl":"https://github.com/xai-org/grok-build/blob/bc7f02eddd3d84085849dc19ed216f11c23b0571/crates/codegen/xai-grok-shell/src/agent/proxy.rs#L188-L224","documentation":"`tls_wrap` throws this when `rustls::pki_types::ServerName::try_from(server_name)` fails to parse the target hostname into a valid TLS server name. rustls only accepts well-formed DNS names, IP addresses, or exact forms; names with invalid characters, empty strings, embedded whitespace, underscores in invalid positions, or other malformed input are rejected before any handshake is attempted. This is a pre-handshake validation error in `connect_via_proxy` — the tunnel may be fine, but the name cannot be used for the TLS ClientHello/certificate verification.","triggerScenarios":"`connect_via_proxy(proxy_url, target_host, target_port)` is called with a `target_host` that is not a valid rustls `ServerName`: empty string, uppercase-with-invalid-chars, a URL instead of a bare hostname (e.g. `https://api.example.com/` passed as host), an IDN in raw Unicode form rather than punycode, or trailing whitespace.","commonSituations":"Passing a full URL or `host:port` string where only the bare hostname should go; extracting the host from a config with surrounding whitespace; internationalized domain names not converted to ASCII punycode; using an IP-literal with a zone id (e.g. `fe80::1%eth0`) that rustls rejects.","solutions":["Pass only the bare hostname (no scheme, no port, no trailing slash) as `target_host` to `connect_via_proxy` — strip these before calling","Validate the hostname before connecting (e.g. check it is non-empty and matches a DNS-name pattern, or run it through `rustls::pki_types::ServerName::try_from` yourself and surface a clear config error)","Convert internationalized names to punycode (IDNA) before passing them","Trim whitespace from config-sourced hostnames"],"exampleFix":"// before\nlet host = \"https://api.example.com/\";\nconnect_via_proxy(&proxy, host, 443).await?;\n// after\nlet host = url.parse::<url::Url>()?.host_str().unwrap_or_default().trim().to_string();\nconnect_via_proxy(&proxy, &host, 443).await?;","handlingStrategy":"validation","validationCode":"fn validate_tls_server_name(host: &str) -> Result<String, String> {\n    let name = host.trim();\n    if name.is_empty() {\n        return Err(\"target host is empty\".into());\n    }\n    // Reject scheme/port/path leakage — only a bare hostname/IP is valid.\n    if name.contains(\"//\") || name.contains('/') || name.contains(':') || name.contains(' ') {\n        return Err(format!(\"'{host}' is not a bare hostname (strip scheme/port/path)\"));\n    }\n    rustls::pki_types::ServerName::try_from(name.to_string())\n        .map(|_| name.to_string())\n        .map_err(|e| format!(\"invalid TLS server name '{name}': {e}\"))\n}","typeGuard":"fn is_valid_server_name(name: &str) -> bool {\n    rustls::pki_types::ServerName::try_from(name.trim().to_string()).is_ok()\n}","tryCatchPattern":"match tls_wrap(stream, server_name).await {\n    Err(e) if e.to_string().starts_with(\"Invalid TLS server name\") => {\n        eprintln!(\"Fix target_host: must be a bare DNS name or IP, got '{server_name}'\");\n    }\n    r => r?,\n}","preventionTips":["Always pass the bare hostname (no scheme, port, path, or whitespace) as target_host","Convert internationalized domain names to punycode before connecting","Validate config-sourced hostnames at startup, not at connect time","Never pass a full URL string where a hostname is expected"],"tags":["tls","rustls","validation","proxy"],"backgroundTag":"invalid-tls-server-name","analyzedSha":"bc7f02eddd3d84085849dc19ed216f11c23b0571","analyzedAt":"2026-08-31T04:59:42.031Z","schemaVersion":2},"datasetVersion":"2026-08-31T09:17:48.483Z"}