{"record":{"id":"f8fd02dc615031dc","repo":"block/buzz","slug":"buzz-uds-path-uds-path-exists-but-is-not-a-socke","errorCode":null,"errorMessage":"BUZZ_UDS_PATH {uds_path} exists but is not a socket","messagePattern":"BUZZ_UDS_PATH (.+?) exists but is not a socket","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/buzz-relay/src/main.rs","lineNumber":1459,"sourceCode":"            \"Signalled restart close to all live WebSocket connections\"\n        );\n        hard_shutdown_abort\n    });\n\n    let tcp_listener = tokio::net::TcpListener::bind(&config.bind_addr)\n        .await\n        .map_err(|e| anyhow::anyhow!(\"Failed to bind {}: {e}\", config.bind_addr))?;\n    info!(addr = %config.bind_addr, \"buzz-relay TCP listening\");\n\n    #[cfg(unix)]\n    if let Some(ref uds_path) = config.uds_path {\n        use std::os::unix::fs::FileTypeExt as _;\n        match std::fs::symlink_metadata(uds_path) {\n            Ok(meta) if meta.file_type().is_socket() => {\n                let _ = std::fs::remove_file(uds_path);\n            }\n            Ok(_) => {\n                return Err(anyhow::anyhow!(\n                    \"BUZZ_UDS_PATH {uds_path} exists but is not a socket\"\n                ));\n            }\n            Err(_) => {}\n        }\n        let uds_listener = tokio::net::UnixListener::bind(uds_path)\n            .map_err(|e| anyhow::anyhow!(\"Failed to bind UDS {uds_path}: {e}\"))?;\n        info!(path = %uds_path, \"buzz-relay UDS listening\");\n\n        let router_uds = router.clone();\n        let mut uds_rx = shutdown_tx.subscribe();\n        let uds_handle = tokio::spawn(async move {\n            axum::serve(uds_listener, router_uds.into_make_service())\n                .with_graceful_shutdown(async move {\n                    uds_rx.changed().await.ok();\n                })\n                .await\n                .ok();","sourceCodeStart":1441,"sourceCodeEnd":1477,"githubUrl":"https://github.com/block/buzz/blob/ef2aa1ae38fadcc0bc22b8bf6ed96b35933146be/crates/buzz-relay/src/main.rs#L1441-L1477","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"# before\nexport BUZZ_UDS_PATH=/var/run/buzz.sock\n# ls -l /var/run/buzz.sock  -> regular file touched by systemd unit\n# error: BUZZ_UDS_PATH /var/run/buzz.sock exists but is not a socket\n\n# after\nrm /var/run/buzz.sock\n# relay restart removes stale *socket* entries automatically from now on","handlingStrategy":"validation","validationCode":"# before starting with BUZZ_UDS_PATH set, verify the path is absent or a socket\np=\"$BUZZ_UDS_PATH\"\nif [ -e \"$p\" ] && [ \"$(stat -c %F \"$p\")\" != \"socket\" ]; then\n  echo \"$p exists and is not a socket\" >&2; exit 1\nfi","typeGuard":"fn is_socket_or_absent(p: &std::path::Path) -> bool {\n    use std::os::unix::fs::FileTypeExt;\n    match std::fs::symlink_metadata(p) {\n        Ok(m) => m.file_type().is_socket(),\n        Err(_) => true,\n    }\n}","tryCatchPattern":null,"preventionTips":["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."],"tags":["rust","unix","uds","unix-socket","startup","filesystem"],"backgroundTag":"invalid-file-type","analyzedSha":"ef2aa1ae38fadcc0bc22b8bf6ed96b35933146be","analyzedAt":"2026-08-20T04:38:24.874Z","contentChangedAt":"2026-08-20T04:38:24.874Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}