xai-org/grok-build · error
bind {}: {e}
Error message
bind {}: {e} What it means
serve() failed to bind the diagnostics Unix domain socket at the given path. Any existing socket file is removed first, so this error comes from the OS refusing the bind (unwritable/nonexistent parent directory, path too long, or a race where another process re-created the socket). The diag server never starts.
Source
Thrown at crates/codegen/xai-grok-diag-server/src/lib.rs:412
/// Bind the listener and spawn the server task.
/// Binding happens before this returns, so a bind failure surfaces synchronously.
/// `log_file` is the daemon log served by `/logs` (`None` means `/logs` is 404).
pub async fn serve(
listener: DiagListener,
handle: DiagHandle,
log_file: Option<PathBuf>,
) -> anyhow::Result<BoundDiag> {
let ctx = DiagContext {
handle,
log_file: log_file.map(Arc::new),
};
match listener {
#[cfg(unix)]
DiagListener::Unix(path) => {
let _ = fs::remove_file(&path);
let listener =
UnixListener::bind(&path).map_err(|e| anyhow!("bind {}: {e}", path.display()))?;
use std::os::unix::fs::PermissionsExt as _;
if let Err(e) = fs::set_permissions(&path, fs::Permissions::from_mode(0o600)) {
tracing::warn!(
path = %path.display(),
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,
})View on GitHub (pinned to bc7f02eddd)
Solutions
- Verify the socket's parent directory exists and is writable by the current user; create it if needed
- Shorten the socket path (e.g. use a shorter tmp dir) if it exceeds the Unix socket path limit
- Check no other live process owns the socket path (ss -x | grep <name>) and stop it
- Run in an environment (container/sandbox) that permits creating Unix sockets in the chosen directory
Example fix
// before
let path = "/very/long/cache/path/with/many/components/grok-diag.sock";
// after
let path = std::env::temp_dir().join("grok-diag.sock"); // short, guaranteed-writable path Defensive patterns
Strategy: validation
Validate before calling
let dir = path.parent().expect("socket path has parent");
if !dir.exists() {
std::fs::create_dir_all(dir)?;
}
if path.as_os_str().len() > 100 {
return Err(anyhow!("socket path too long: {}", path.display()));
} Type guard
fn socket_path_ok(path: &std::path::Path) -> bool {
path.parent().map(|d| d.is_dir()).unwrap_or(false)
&& path.as_os_str().len() <= 100
} Try / catch
match serve(ctx, DiagListener::Unix(path)).await {
Ok(h) => h,
Err(e) if e.to_string().starts_with("bind ") => {
eprintln!("diag unix socket bind failed: {e:#}; check dir permissions/path length");
return Err(e);
}
Err(e) => return Err(e),
} Prevention
- Ensure the socket directory exists and is writable before serve()
- Keep Unix socket paths short (use temp_dir or XDG_RUNTIME_DIR)
- Check for other processes bound to the same socket path (ss -x)
- Account for sandbox/container filesystem restrictions
When it happens
Trigger: DiagListener::Unix(path) where the parent directory does not exist or is not writable, the socket path exceeds the ~104-char Unix socket limit, or another process concurrently holds the path as a live socket.
Common situations: XDG_RUNTIME_DIR or temp dir cleaned up/never created; running under a sandbox/container without write access to the socket directory; very long cache paths exceeding sockaddr_un limits.
Related errors
- unmount {}: {err}
- bind 127.0.0.1:{port}: {e}
- clear failed
- Failed to enable plugin: {e}
- Failed to disable plugin: {e}
AI-assisted analysis of xai-org/grok-build@bc7f02eddd (2026-08-31).
Data as JSON: /api/errors/a815e32f5584241a.
Report an issue: GitHub.