{"record":{"id":"8397fe7055308657","repo":"vercel/turborepo","slug":"daemon-socket-parent-is-not-a-directory-socket-d","errorCode":null,"errorMessage":"daemon socket parent is not a directory: {socket_dir}","messagePattern":"daemon socket parent is not a directory: (.+?)","errorType":"exception","errorClass":"std::io::Error","httpStatus":null,"severity":"error","filePath":"crates/turborepo-daemon/src/endpoint.rs","lineNumber":498,"sourceCode":"    })?;\n    if let Some(daemon_dir) = socket_dir.parent() {\n        secure_unix_dir(daemon_dir)?;\n    }\n    secure_unix_dir(socket_dir)\n}\n\n#[cfg(unix)]\nfn secure_unix_dir(socket_dir: &AbsoluteSystemPath) -> Result<(), std::io::Error> {\n    use std::os::unix::fs::{DirBuilderExt, MetadataExt, PermissionsExt};\n\n    std::fs::DirBuilder::new()\n        .recursive(true)\n        .mode(PRIVATE_DIR_MODE)\n        .create(socket_dir.as_std_path())?;\n\n    let metadata = std::fs::symlink_metadata(socket_dir.as_std_path())?;\n    if !metadata.file_type().is_dir() {\n        return Err(std::io::Error::new(\n            std::io::ErrorKind::PermissionDenied,\n            format!(\"daemon socket parent is not a directory: {socket_dir}\"),\n        ));\n    }\n    if metadata.uid() != current_uid() {\n        return Err(std::io::Error::new(\n            std::io::ErrorKind::PermissionDenied,\n            format!(\"daemon socket parent is owned by another user: {socket_dir}\"),\n        ));\n    }\n\n    let mode = metadata.permissions().mode() & 0o777;\n    if mode != PRIVATE_DIR_MODE {\n        std::fs::set_permissions(\n            socket_dir.as_std_path(),\n            std::fs::Permissions::from_mode(PRIVATE_DIR_MODE),\n        )?;\n    }","sourceCodeStart":480,"sourceCodeEnd":516,"githubUrl":"https://github.com/vercel/turborepo/blob/f9245100cf0d31d96628804ead485f6bf226e55a/crates/turborepo-daemon/src/endpoint.rs#L480-L516","documentation":"On Unix, secure_unix_dir (endpoint.rs:498) creates the socket parent dir with mode 0700, then stats it with symlink_metadata and requires file_type().is_dir(). This PermissionDenied error means something other than a directory occupies the path — a regular file, FIFO, or notably a symlink (lstat does not follow links, so a symlink-to-directory also fails the check). The daemon refuses to operate through a swappable path.","triggerScenarios":"Daemon start when the socket dir path (e.g. ~/.cache/turborepo or XDG_RUNTIME_DIR/turborepo) is occupied by a file or symlink left by another tool, a dotfile manager, or a previous mishap.","commonSituations":"Users symlinking cache/runtime dirs to tmpfs or a shared folder Another application claiming the same directory name Leftover artifacts from a crashed daemon or manual experiments","solutions":["Inspect the path in the message with `ls -la` / `file <path>`","Remove the non-directory entry (rm the file, or unlink the symlink — do not delete through it)","Restart the daemon (turbo daemon restart) so it recreates a real directory"],"exampleFix":"# bash: inspect and clear the offending entry\nfile ~/.cache/turborepo\nrm -i ~/.cache/turborepo   # or: unlink ~/.cache/turborepo if a symlink\nturbo daemon restart","handlingStrategy":"validation","validationCode":"// before daemon start, ensure the socket parent is a real directory\nlet m = std::fs::symlink_metadata(socket_dir)?; // lstat: does not follow symlinks\nif !m.is_dir() {\n    anyhow::bail!(\"{socket_dir} exists but is not a directory\");\n}","typeGuard":"fn is_real_dir(p: &Path) -> bool {\n    std::fs::symlink_metadata(p).map(|m| m.is_dir()).unwrap_or(false)\n}","tryCatchPattern":"match daemon_start() {\n    Err(e) if e.kind() == std::io::ErrorKind::PermissionDenied\n        && e.to_string().contains(\"not a directory\") => { std::fs::remove_file(socket_dir).ok(); daemon_start()? }\n    r => r,\n}","preventionTips":["Do not symlink the daemon/cache runtime dir; mount tmpfs instead","Check `file <path>` when reusing nonstandard runtime dirs"],"tags":["daemon","unix","socket","filesystem","symlink"],"backgroundTag":"path-is-not-a-directory","analyzedSha":"f9245100cf0d31d96628804ead485f6bf226e55a","analyzedAt":"2026-08-17T10:46:15.696Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}