xai-org/grok-build · error
bind 127.0.0.1:{port}: {e}
Error message
bind 127.0.0.1:{port}: {e} What it means
serve() failed to bind the diagnostics TCP listener on 127.0.0.1:{port}. Tokio's TcpListener::bind returned an OS error (address in use, permission denied, etc.) which is wrapped into this anyhow error. The diagnostics HTTP server cannot start, so all readiness/statusz checks against it fail.
Source
Thrown at crates/codegen/xai-grok-diag-server/src/lib.rs:435
error = %e,
"failed to restrict diagnostics socket permissions"
);
}
let task = tokio::spawn(async move {
if let Err(e) = axum::serve(listener, router(ctx)).await {
tracing::warn!(error = %e, "diagnostics server exited");
}
});
Ok(BoundDiag {
addr: format!("unix:{}", path.display()),
port: None,
task,
})
}
DiagListener::Tcp(port) => {
let listener = TcpListener::bind((Ipv4Addr::LOCALHOST, port))
.await
.map_err(|e| anyhow!("bind 127.0.0.1:{port}: {e}"))?;
let local = listener.local_addr()?;
let task = tokio::spawn(async move {
if let Err(e) = axum::serve(listener, router(ctx)).await {
tracing::warn!(error = %e, "diagnostics server exited");
}
});
Ok(BoundDiag {
addr: format!("http://{local}"),
port: Some(local.port()),
task,
})
}
}
}
#[derive(Debug)]
pub struct BoundDiag {
/// Human-readable bound address for the startup log line.View on GitHub (pinned to bc7f02eddd)
Solutions
- Find and stop the process occupying the port (lsof -i :PORT / ss -ltnp), or kill the stale diag server
- Choose a different, free port for the diagnostics listener
- If binding a privileged port, run with sufficient privileges or pick a port >1024
- Retry after a moment if a just-killed process is in TIME_WAIT
Example fix
// before DiagListener::Tcp(8080) // after DiagListener::Tcp(0) // let the OS pick a free ephemeral port, then read listener.local_addr()
Defensive patterns
Strategy: fallback
Validate before calling
// probe the port before binding
if std::net::TcpListener::bind((std::net::Ipv4Addr::LOCALHOST, port)).is_err() {
eprintln!("port {port} in use; pick another");
}
Type guard
fn port_free(port: u16) -> bool {
std::net::TcpListener::bind((std::net::Ipv4Addr::LOCALHOST, port)).is_ok()
} Try / catch
match serve(ctx, DiagListener::Tcp(port)).await {
Err(e) if e.to_string().contains("bind 127.0.0.1") => {
eprintln!("diag TCP bind failed on {port}: {e:#}");
// fallback: retry with port 0 to let the OS choose
serve(ctx, DiagListener::Tcp(0)).await
}
other => other,
} Prevention
- Use port 0 (ephemeral) and read back listener.local_addr() in tests/CI
- Ensure only one diag server instance runs per machine (pidfile or lock)
- Avoid privileged ports (<1024) unless running with adequate privileges
- Wait for TIME_WAIT to clear or set SO_REUSEADDR semantics via the runtime
When it happens
Trigger: Starting the diag server with DiagListener::Tcp(port) when the port is already bound by another process, the port is privileged (<1024) without permissions, or ipv4 loopback bind fails for another OS reason.
Common situations: Two diag server instances running concurrently (stale process from a previous session); port collision with another dev service; CI containers reusing a fixed port; configured port 80/443 without root.
Related errors
- bind {}: {e}
- Failed to connect to proxy at {proxy_addr}: {e}
- OidcError::BindLoopback
- send failed: {body}
- screen query failed: {body}
AI-assisted analysis of xai-org/grok-build@bc7f02eddd (2026-08-31).
Data as JSON: /api/errors/7617439c6129c4af.
Report an issue: GitHub.