{"record":{"id":"8537c786e0cbad1e","repo":"facebook/flow","slug":"socket-path-has-no-basename","errorCode":null,"errorMessage":"socket path has no basename","messagePattern":"socket path has no basename","errorType":"validation","errorClass":"std::io::Error","httpStatus":null,"severity":"error","filePath":"rust_port/crates/flow_common_socket/src/socket.rs","lineNumber":51,"sourceCode":"    #[cfg(unix)]\n    Unix(String),\n}\n\n// On Linux/Mac/BSD, sockaddr_un.sun_path is a fixed length. To handle longer paths,\n// we chdir to that directory and use a relative path instead. The callback provides\n// a Unix.sockaddr with a relative path that you can use to bind or read from. Perform\n// as little as possible within the callback, since it has an unexpected working dir.\n// This function tries to make it awkward for the Unix.sockaddr with the relative path\n// to escape from the callback.\n#[cfg(unix)]\npub fn with_addr<T>(addr: &Addr, f: impl FnOnce(&SockAddr) -> io::Result<T>) -> io::Result<T> {\n    let cwd = std::env::current_dir()?;\n    match addr {\n        Addr::Unix(file) => {\n            let path = Path::new(file);\n            let dir = path.parent().unwrap_or_else(|| Path::new(\".\"));\n            let base = path.file_name().ok_or_else(|| {\n                io::Error::new(io::ErrorKind::InvalidInput, \"socket path has no basename\")\n            })?;\n            std::env::set_current_dir(dir)?;\n            let mut guard = CwdGuard(Some(cwd));\n            let sockaddr = SockAddr::unix(Path::new(\".\").join(base))?;\n            let result = f(&sockaddr);\n            guard.restore()?;\n            result\n        }\n    }\n}\n\n// Initializes the unix domain socket\nfn unix_socket(sock_name: &str) -> io::Result<SocketListener> {\n    flow_common::sys_utils::with_umask(0o111, || {\n        let dir = Path::new(sock_name)\n            .parent()\n            .filter(|dir| !dir.as_os_str().is_empty())\n            .unwrap_or_else(|| Path::new(\".\"));","sourceCodeStart":33,"sourceCodeEnd":69,"githubUrl":"https://github.com/facebook/flow/blob/f88ac94bcf6992f5d5a158854d94613ebb92c6e6/rust_port/crates/flow_common_socket/src/socket.rs#L33-L69","documentation":"with_addr runs a Unix-socket operation by chdir-ing into the socket's parent directory and binding/connecting to ./basename; this keeps the sockaddr path short (Unix addr length limits) and prevents the relative sockaddr from escaping the callback. It requires the socket path to have a final component: paths whose Path::file_name() is None — \"/\", \"..\", or anything ending in a parent component — are rejected up front with ErrorKind::InvalidInput before any socket work happens.","triggerScenarios":"Constructing Addr::Unix from a path like Path::new(\"/\"), \"..\", or \"foo/../..\" (file_name() returns None for all of these) and passing it to with_addr, which SocketStream/UnixListener bind and connect paths go through.","commonSituations":"Socket path assembled by joining config values that collapse to \"..\" or that end with a separator (e.g. format!(\"{dir}/\") with no filename appended); empty socket-dir config; a templated path whose filename variable is unset.","solutions":["Pass a concrete socket file path with a real basename, e.g. /tmp/flow-standalone.sock.","Validate the configured socket path before startup: path.file_name() must be Some and non-empty.","Log the final resolved socket path at startup so a misjoined path is visible immediately."],"exampleFix":"// before: joining a dir with nothing yields a path with no basename\nlet sock = dir.join(\"\"); // dir == \"../run\" -> file_name() == None -> \"socket path has no basename\"\n\n// after: always append an explicit socket file name\nlet sock = dir.join(\"flow.sock\");\nassert!(sock.file_name().is_some());","handlingStrategy":"validation","validationCode":"use std::path::Path;\n\nfn has_socket_basename(p: &Path) -> bool {\n    p.file_name().map(|f| !f.is_empty()).unwrap_or(false)\n}\n\n// call before constructing Addr::Unix / calling with_addr\nassert!(has_socket_basename(Path::new(&sock_path)));","typeGuard":"fn is_no_basename_error(e: &std::io::Error) -> bool {\n    e.kind() == std::io::ErrorKind::InvalidInput && e.to_string().contains(\"no basename\")\n}","tryCatchPattern":"Fail fast on InvalidInput 'no basename': include the offending path in the error you surface. This is a configuration bug, not a transient condition — retrying will not help.","preventionTips":["Always build socket paths as dir.join(\"name.sock\") with a literal basename.","Assert file_name().is_some() on any socket path coming from config before startup.","Log the final socket path at server startup."],"tags":["unix-socket","path-validation","invalid-input","rust"],"backgroundTag":"invalid-socket-path","analyzedSha":"f88ac94bcf6992f5d5a158854d94613ebb92c6e6","analyzedAt":"2026-08-20T10:41:37.992Z","contentChangedAt":"2026-08-20T10:41:37.992Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}