facebook/flow · error · std::io::Error

socket path has no basename

Error message

socket path has no basename

What it means

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.

Source

Thrown at rust_port/crates/flow_common_socket/src/socket.rs:51

    #[cfg(unix)]
    Unix(String),
}

// On Linux/Mac/BSD, sockaddr_un.sun_path is a fixed length. To handle longer paths,
// we chdir to that directory and use a relative path instead. The callback provides
// a Unix.sockaddr with a relative path that you can use to bind or read from. Perform
// as little as possible within the callback, since it has an unexpected working dir.
// This function tries to make it awkward for the Unix.sockaddr with the relative path
// to escape from the callback.
#[cfg(unix)]
pub fn with_addr<T>(addr: &Addr, f: impl FnOnce(&SockAddr) -> io::Result<T>) -> io::Result<T> {
    let cwd = std::env::current_dir()?;
    match addr {
        Addr::Unix(file) => {
            let path = Path::new(file);
            let dir = path.parent().unwrap_or_else(|| Path::new("."));
            let base = path.file_name().ok_or_else(|| {
                io::Error::new(io::ErrorKind::InvalidInput, "socket path has no basename")
            })?;
            std::env::set_current_dir(dir)?;
            let mut guard = CwdGuard(Some(cwd));
            let sockaddr = SockAddr::unix(Path::new(".").join(base))?;
            let result = f(&sockaddr);
            guard.restore()?;
            result
        }
    }
}

// Initializes the unix domain socket
fn unix_socket(sock_name: &str) -> io::Result<SocketListener> {
    flow_common::sys_utils::with_umask(0o111, || {
        let dir = Path::new(sock_name)
            .parent()
            .filter(|dir| !dir.as_os_str().is_empty())
            .unwrap_or_else(|| Path::new("."));

View on GitHub (pinned to f88ac94bcf)

Solutions

  1. Pass a concrete socket file path with a real basename, e.g. /tmp/flow-standalone.sock.
  2. Validate the configured socket path before startup: path.file_name() must be Some and non-empty.
  3. Log the final resolved socket path at startup so a misjoined path is visible immediately.

Example fix

// before: joining a dir with nothing yields a path with no basename
let sock = dir.join(""); // dir == "../run" -> file_name() == None -> "socket path has no basename"

// after: always append an explicit socket file name
let sock = dir.join("flow.sock");
assert!(sock.file_name().is_some());
Defensive patterns

Strategy: validation

Validate before calling

use std::path::Path;

fn has_socket_basename(p: &Path) -> bool {
    p.file_name().map(|f| !f.is_empty()).unwrap_or(false)
}

// call before constructing Addr::Unix / calling with_addr
assert!(has_socket_basename(Path::new(&sock_path)));

Type guard

fn is_no_basename_error(e: &std::io::Error) -> bool {
    e.kind() == std::io::ErrorKind::InvalidInput && e.to_string().contains("no basename")
}

Try / catch

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.

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of facebook/flow@f88ac94bcf (2026-08-20). Data as JSON: /api/errors/8537c786e0cbad1e. Report an issue: GitHub.