block/buzz · error · anyhow::Error
BUZZ_UDS_PATH exists but is not a socket
Error message
BUZZ_UDS_PATH {uds_path} exists but is not a socket What it means
When BUZZ_UDS_PATH is set on Unix, serve() inspects the path with symlink_metadata before binding a Unix domain socket. If an entry exists, is a socket file left by a previous run, it is silently removed; anything else (regular file, directory, symlink — note symlink_metadata does not follow symlinks, so a symlink's own type is 'symlink') is a hard error. The check protects against both destroying user data at that path and binding a socket behind an attacker-controlled indirection.
Solutions
- Inspect the existing entry: `ls -l <path>` / `file <path>`.
- If it is a stale regular file or symlink you control, remove it: `rm <path>` (or `rmdir` for a directory) and restart the relay.
- If the path belongs to another service, choose a different BUZZ_UDS_PATH (e.g. /run/buzz-relay.sock).
- If you intended socket-activation-style symlink indirection, drop it — bind the real socket path directly; the relay will not follow symlinks for UDS.
- Fix provisioning scripts to `rm -f` the socket path instead of `touch`ing it.
Example fix
# before export BUZZ_UDS_PATH=/var/run/buzz.sock # ls -l /var/run/buzz.sock -> regular file touched by systemd unit # error: BUZZ_UDS_PATH /var/run/buzz.sock exists but is not a socket # after rm /var/run/buzz.sock # relay restart removes stale *socket* entries automatically from now on
Defensive patterns
Strategy: validation
Validate before calling
# before starting with BUZZ_UDS_PATH set, verify the path is absent or a socket p="$BUZZ_UDS_PATH" if [ -e "$p" ] && [ "$(stat -c %F "$p")" != "socket" ]; then echo "$p exists and is not a socket" >&2; exit 1 fi
Type guard
fn is_socket_or_absent(p: &std::path::Path) -> bool {
use std::os::unix::fs::FileTypeExt;
match std::fs::symlink_metadata(p) {
Ok(m) => m.file_type().is_socket(),
Err(_) => true,
}
} Prevention
- Never pre-create the UDS path with touch/mkdir in provisioning scripts; let the relay create it.
- Avoid symlinking the socket path — the relay's symlink_metadata check refuses to follow links by design.
- Give each relay instance its own socket filename so stale files are obviously attributable.
- Clean up sockets in systemd ExecStartPre (`rm -f /run/buzz/relay.sock`) with -f only, never rmdir/mv of foreign entries.
When it happens
Trigger: Setting BUZZ_UDS_PATH to: (1) a path occupied by a regular file (e.g. a config or log file); (2) an existing directory; (3) a symlink pointing at the real socket location — symlink_metadata reports the link itself, which is not a socket, so this errors instead of silently unlinking through the link; (4) a leftover FIFO or device node. Only a concrete socket file at that exact path is auto-cleaned.
Common situations: BUZZ_UDS_PATH=/var/run/buzz.sock where /var/run/buzz.sock was pre-created with `touch` by a provisioning script; pointing the env var at a symlink placed by an init system that manages socket activation; reusing a path that another daemon already uses for its own non-socket state.
Related errors
- Failed to bind UDS
- git pack cache path must be available
- oauth cache is not a regular file
- Failed to bind
- Failed to bind health port
AI-assisted analysis of block/buzz@ef2aa1ae38 (2026-08-20).
Data as JSON: /api/errors/f8fd02dc615031dc.
Report an issue: GitHub.
Appendix: source
Thrown at crates/buzz-relay/src/main.rs:1459
"Signalled restart close to all live WebSocket connections"
);
hard_shutdown_abort
});
let tcp_listener = tokio::net::TcpListener::bind(&config.bind_addr)
.await
.map_err(|e| anyhow::anyhow!("Failed to bind {}: {e}", config.bind_addr))?;
info!(addr = %config.bind_addr, "buzz-relay TCP listening");
#[cfg(unix)]
if let Some(ref uds_path) = config.uds_path {
use std::os::unix::fs::FileTypeExt as _;
match std::fs::symlink_metadata(uds_path) {
Ok(meta) if meta.file_type().is_socket() => {
let _ = std::fs::remove_file(uds_path);
}
Ok(_) => {
return Err(anyhow::anyhow!(
"BUZZ_UDS_PATH {uds_path} exists but is not a socket"
));
}
Err(_) => {}
}
let uds_listener = tokio::net::UnixListener::bind(uds_path)
.map_err(|e| anyhow::anyhow!("Failed to bind UDS {uds_path}: {e}"))?;
info!(path = %uds_path, "buzz-relay UDS listening");
let router_uds = router.clone();
let mut uds_rx = shutdown_tx.subscribe();
let uds_handle = tokio::spawn(async move {
axum::serve(uds_listener, router_uds.into_make_service())
.with_graceful_shutdown(async move {
uds_rx.changed().await.ok();
})
.await
.ok();View on GitHub (pinned to ef2aa1ae38)