xai-org/grok-build · error
Invalid TLS server name '{server_name}': {e}
Error message
Invalid TLS server name '{server_name}': {e} What it means
`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.
Source
Thrown at crates/codegen/xai-grok-shell/src/agent/proxy.rs:206
if !remaining.is_empty() {
anyhow::bail!(
"Proxy sent {} unexpected byte(s) after CONNECT response headers",
remaining.len()
);
}
// 6. Reunite the split halves back into a TcpStream.
let stream = reader.into_inner().reunite(writer_half)?;
Ok(stream)
}
async fn tls_wrap(
stream: TcpStream,
server_name: &str,
) -> anyhow::Result<tokio_rustls::client::TlsStream<TcpStream>> {
let connector = tokio_rustls::TlsConnector::from(xai_grok_extra_ca::rustls_client_config());
let dns_name = rustls::pki_types::ServerName::try_from(server_name.to_string())
.map_err(|e| anyhow::anyhow!("Invalid TLS server name '{server_name}': {e}"))?;
let tls_stream = connector
.connect(dns_name, stream)
.await
.map_err(|e| anyhow::anyhow!("TLS handshake through proxy failed: {e}"))?;
Ok(tls_stream)
}
/// Parse a proxy URL into (host, port).
///
/// Accepted formats:
/// - `http://host:port`
/// - `http://host` (defaults to port 80)
/// - `host:port`
fn parse_proxy_url(url: &str) -> anyhow::Result<(String, u16)> {
// Strip scheme if present.
let without_scheme = urlView on GitHub (pinned to bc7f02eddd)
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
Example fix
// before let host = "https://api.example.com/"; connect_via_proxy(&proxy, host, 443).await?; // after let host = url.parse::<url::Url>()?.host_str().unwrap_or_default().trim().to_string(); connect_via_proxy(&proxy, &host, 443).await?;
Defensive patterns
Strategy: validation
Validate before calling
fn validate_tls_server_name(host: &str) -> Result<String, String> {
let name = host.trim();
if name.is_empty() {
return Err("target host is empty".into());
}
// Reject scheme/port/path leakage — only a bare hostname/IP is valid.
if name.contains("//") || name.contains('/') || name.contains(':') || name.contains(' ') {
return Err(format!("'{host}' is not a bare hostname (strip scheme/port/path)"));
}
rustls::pki_types::ServerName::try_from(name.to_string())
.map(|_| name.to_string())
.map_err(|e| format!("invalid TLS server name '{name}': {e}"))
} Type guard
fn is_valid_server_name(name: &str) -> bool {
rustls::pki_types::ServerName::try_from(name.trim().to_string()).is_ok()
} Try / catch
match tls_wrap(stream, server_name).await {
Err(e) if e.to_string().starts_with("Invalid TLS server name") => {
eprintln!("Fix target_host: must be a bare DNS name or IP, got '{server_name}'");
}
r => r?,
} Prevention
- 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
When it happens
Trigger: `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.
Common situations: 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.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- TLS handshake through proxy failed: {e}
- Proxy sent {} unexpected byte(s) after CONNECT response head
- aws-lc-rs supports the default protocol versions
- invalid worktree id from dest: {worktree_id}
- invalid worktree id {:?}
AI-assisted analysis of xai-org/grok-build@bc7f02eddd (2026-08-31).
Data as JSON: /api/errors/0cf4b9f145f63b01.
Report an issue: GitHub.