{"record":{"id":"e084ac81a1d0a640","repo":"openai/codex","slug":"invalidinput-e084ac","errorCode":"InvalidInput","errorMessage":"path is a directory","messagePattern":"path is a directory","errorType":"exception","errorClass":"std::io::Error","httpStatus":null,"severity":"error","filePath":"codex-rs/apply-patch/src/lib.rs","lineNumber":738,"sourceCode":"    }\n    Ok(AffectedPaths {\n        added,\n        modified,\n        deleted,\n    })\n}\n\nasync fn ensure_not_directory(\n    path: &PathUri,\n    fs: &dyn ExecutorFileSystem,\n    follow_symlinks: bool,\n    sandbox: Option<&FileSystemSandboxContext>,\n) -> io::Result<()> {\n    let metadata = fs\n        .get_metadata(path, GetMetadataOptions { follow_symlinks }, sandbox)\n        .await?;\n    if metadata.is_directory {\n        return Err(io::Error::new(\n            io::ErrorKind::InvalidInput,\n            \"path is a directory\",\n        ));\n    }\n    Ok(())\n}\n\nasync fn remove_failure_was_side_effect_free(\n    path: &PathUri,\n    expected_content: Option<&str>,\n    fs: &dyn ExecutorFileSystem,\n    follow_symlinks: bool,\n    sandbox: Option<&FileSystemSandboxContext>,\n) -> bool {\n    match expected_content {\n        Some(expected_content) => fs\n            .read_file_text(path, ReadFileOptions { follow_symlinks }, sandbox)\n            .await","sourceCodeStart":720,"sourceCodeEnd":756,"githubUrl":"https://github.com/openai/codex/blob/339751715c64496cb86246bfb3935f40e309dd3d/codex-rs/apply-patch/src/lib.rs#L720-L756","documentation":"ensure_not_directory fetches metadata for a target path (honoring the follow_symlinks option) and returns io::ErrorKind::InvalidInput with 'path is a directory' when the path resolves to a directory. apply-patch invokes it before file writes, so a patch that tries to add or update a 'file' whose path is an existing directory fails fast instead of corrupting the directory. It propagates wrapped in ApplyPatchFailure together with the delta of changes already committed.","triggerScenarios":"An '*** Add File:' or '*** Update File:' hunk whose path names an existing directory; a '*** Move to:' destination that is a directory; a symlink that resolves (follow_symlinks=true) to a directory.","commonSituations":"A model-generated patch uses a path that collides with an existing directory (e.g. 'src/utils' where utils is a directory); the repo layout changed between patch generation and application; path-join or trailing-slash bugs producing a directory path.","solutions":["Look at the failing path named in the error context and change the patch so it targets a file path that does not collide with an existing directory","If the directory is stale or wrong, remove or rename it, then re-apply the patch","For '*** Move to:' hunks, make sure the destination is a file path, not a directory","Check symlinks on the path: with follow_symlinks enabled a link can resolve to a directory"],"exampleFix":"# before (patch hunk targets a directory)\n*** Update File: src/utils\n\n# after\n*** Update File: src/utils.rs","handlingStrategy":"validation","validationCode":"for hunk in hunks {\n    let p = cwd.as_path().join(hunk.path());\n    if let Ok(meta) = std::fs::metadata(&p) {\n        if meta.is_dir() {\n            return Err(format!(\"patch target is a directory: {}\", p.display()));\n        }\n    }\n}","typeGuard":null,"tryCatchPattern":"if let Err(failure) = apply_hunks(&hunks, &cwd, &mut out, &mut err, fs, None).await {\n    let (err, _) = failure.into_parts();\n    if let ApplyPatchError::IoError(io) = err {\n        if io.source().kind() == std::io::ErrorKind::InvalidInput { /* directory target */ }\n    }\n}","preventionTips":["Validate every hunk path resolves to a file (or does not exist for Add) before applying","Reject '*** Move to:' destinations that are directories","Remember symlinks: with follow_symlinks enabled a link can resolve to a directory"],"tags":["rust","apply-patch","filesystem","invalid-input"],"backgroundTag":"path-is-a-directory","analyzedSha":"339751715c64496cb86246bfb3935f40e309dd3d","analyzedAt":"2026-08-25T05:35:09.876Z","schemaVersion":2},"datasetVersion":"2026-08-25T06:17:31.827Z"}