block/buzz · error

BUZZ_UDS_PATH {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() stats the path with std::fs::symlink_metadata before binding. A stale socket file is auto-removed, but any other existing entry — regular file, directory, FIFO, or a symlink (symlink_metadata does not follow links, so even a symlink to a socket fails the is_socket() check) — is fatal with this error. The guard exists so the relay never deletes operator data just to create its socket.

Source

Thrown at crates/buzz-relay/src/main.rs:1343

            "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 f956e6fe06)

Solutions

  1. Inspect the path: ls -la <path> and file <path> to see what it actually is.
  2. If disposable, remove it (rm for files, rmdir for empty dirs) or repoint BUZZ_UDS_PATH to a clean path.
  3. In containers, mount the parent directory (not the socket file path) so the relay can create a normal socket inside it.
  4. If a symlink was intentional, remove it — the relay will neither follow nor replace symlinks.

Example fix

# before: Error: BUZZ_UDS_PATH /run/buzz/buzz.sock exists but is not a socket
# (a directory was created by a file bind-mount)
docker run -v /run/buzz/buzz.sock:/run/buzz/buzz.sock ...

# after: mount the parent directory instead
docker run -v /run/buzz:/run/buzz ...
Defensive patterns

Strategy: validation

Validate before calling

// Before starting the relay, verify the UDS path is absent or a socket:
fn uds_path_clear(path: &std::path::Path) -> bool {
    match std::fs::symlink_metadata(path) {
        Err(_) => true,
        Ok(meta) => meta.file_type().is_socket(),
    }
}

if let Some(uds) = std::env::var("BUZZ_UDS_PATH").ok() {
    assert!(uds_path_clear(std::path::Path::new(&uds)),
        "{uds} exists and is not a socket — remove it or repoint BUZZ_UDS_PATH");
}

Type guard

use std::os::unix::fs::FileTypeExt as _;

fn uds_conflict_kind(path: &std::path::Path) -> Option<&'static str> {
    match std::fs::symlink_metadata(path) {
        Ok(m) if m.is_dir() => Some("directory"),
        Ok(m) if m.file_type().is_symlink() => Some("symlink"),
        Ok(m) if m.file_type().is_socket() => None,
        Ok(_) => Some("regular-file"),
        Err(_) => None,
    }
}

Prevention

When it happens

Trigger: BUZZ_UDS_PATH pointing at an existing regular file (pidfile, log), a directory, or a symlink. The classic container case: bind-mounting a host path over the socket file path makes Docker create a directory exactly where the relay wants to bind.

Common situations: Kubernetes/Docker volumes mounted at the socket path materializing as directories; sharing /run paths with other daemons; leftover artifacts from another program using the same path; operators pre-creating the file for permission reasons.

Related errors


AI-assisted analysis of block/buzz@f956e6fe06 (2026-08-16). Data as JSON: /api/errors/f8fd02dc615031dc. Report an issue: GitHub.