{"record":{"id":"7fafd1f5afd09da1","repo":"windmill-labs/windmill","slug":"path-exists-and-is-not-a-directory","errorCode":null,"errorMessage":"Path '{}' exists and is not a directory","messagePattern":"Path '(.+?)' exists and is not a directory","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"backend/windmill-worker/src/ansible_executor.rs","lineNumber":401,"sourceCode":"    Ok(commit_hash)\n}\n\npub fn create_empty_dir(path: &PathBuf) -> std::io::Result<()> {\n    if path.exists() {\n        if path.is_dir() {\n            let mut entries = std::fs::read_dir(&path)?;\n            if entries.next().is_some() {\n                return Err(std::io::Error::new(\n                    std::io::ErrorKind::AlreadyExists,\n                    format!(\n                        \"Directory '{}' already exists and is not empty\",\n                        path.display()\n                    ),\n                ));\n            }\n            Ok(())\n        } else {\n            Err(std::io::Error::new(\n                std::io::ErrorKind::AlreadyExists,\n                format!(\"Path '{}' exists and is not a directory\", path.display()),\n            ))\n        }\n    } else {\n        std::fs::create_dir_all(path)\n    }\n}\n\n/// Signals a detached `spawn_blocking` task that the future awaiting it is\n/// gone, so it can stop instead of running to completion in the background.\nstruct AbortOnDrop(std::sync::Arc<std::sync::atomic::AtomicBool>);\n\nimpl Drop for AbortOnDrop {\n    fn drop(&mut self) {\n        self.0.store(true, std::sync::atomic::Ordering::Relaxed);\n    }\n}","sourceCodeStart":383,"sourceCodeEnd":419,"githubUrl":"https://github.com/windmill-labs/windmill/blob/e474e8803ce2ff5c2df09a58dab51d45f5c922ca/backend/windmill-worker/src/ansible_executor.rs#L383-L419","documentation":"create_empty_dir prepares a fresh target directory used by archive fetch and git clone paths. If the path already exists but is a regular file, symlink-to-file, or other non-directory entry, it cannot create the directory there and returns io::ErrorKind::AlreadyExists with this message. It exists so callers fail fast instead of clobbering an unexpected file.","triggerScenarios":"Calling create_empty_dir(path) when path exists as a non-directory (regular file or symlink to one), e.g. via fetch_repo_archive or clone_repo_without_history when the workspace/clone target path is occupied by a file.","commonSituations":"A leftover file at the repo checkout path (e.g. a tarball, lock file, or previous failed run wrote a file where a directory was expected); bind-mounted or pre-created files in container paths; case-insensitive filesystems colliding with an existing file.","solutions":["Inspect the path in the message and delete or rename the offending file (rm '<path>' or mv it aside), then re-run the job.","Ensure the target directory passed to fetch_repo_archive/clone_repo_without_history is dedicated and empty; pick a different target path if the file must be kept.","In calling code, check path.is_dir() first and handle the AlreadyExists kind explicitly (e.g. remove_file then retry create_empty_dir)."],"exampleFix":"// before\ncreate_empty_dir(&target)?;\n// after\nif target.exists() && !target.is_dir() {\n    std::fs::remove_file(&target)?;\n}\ncreate_empty_dir(&target)?;","handlingStrategy":"validation","validationCode":"let path = std::path::Path::new(\"/target/dir\");\nif path.exists() && !path.is_dir() {\n    return Err(format!(\"{} exists and is not a directory; remove it first\", path.display()));\n}","typeGuard":"fn is_usable_empty_dir(p: &std::path::Path) -> bool {\n    p.is_dir() && std::fs::read_dir(p).map(|mut d| d.next().is_none()).unwrap_or(false)\n}","tryCatchPattern":"match create_empty_dir(&path) {\n    Err(e) if e.kind() == std::io::ErrorKind::AlreadyExists => {\n        std::fs::remove_file(&path)?;\n        create_empty_dir(&path)?;\n    }\n    other => other?,\n}","preventionTips":["Dedicate a unique, job-scoped target directory per clone/fetch run","Check path.is_dir() before invoking create_empty_dir","Clean up stale artifacts from previous failed runs in the target path"],"tags":["filesystem","io","already-exists","worker"],"backgroundTag":"path-exists-not-a-directory","analyzedSha":"e474e8803ce2ff5c2df09a58dab51d45f5c922ca","analyzedAt":"2026-09-03T12:38:19.024Z","contentChangedAt":"2026-09-03T12:38:19.024Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}