openai/codex · error · std::io::Error
InvalidInput
InvalidInput
Error message
path is a directory
What it means
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.
Source
Thrown at codex-rs/apply-patch/src/lib.rs:738
}
Ok(AffectedPaths {
added,
modified,
deleted,
})
}
async fn ensure_not_directory(
path: &PathUri,
fs: &dyn ExecutorFileSystem,
follow_symlinks: bool,
sandbox: Option<&FileSystemSandboxContext>,
) -> io::Result<()> {
let metadata = fs
.get_metadata(path, GetMetadataOptions { follow_symlinks }, sandbox)
.await?;
if metadata.is_directory {
return Err(io::Error::new(
io::ErrorKind::InvalidInput,
"path is a directory",
));
}
Ok(())
}
async fn remove_failure_was_side_effect_free(
path: &PathUri,
expected_content: Option<&str>,
fs: &dyn ExecutorFileSystem,
follow_symlinks: bool,
sandbox: Option<&FileSystemSandboxContext>,
) -> bool {
match expected_content {
Some(expected_content) => fs
.read_file_text(path, ReadFileOptions { follow_symlinks }, sandbox)
.awaitView on GitHub (pinned to 339751715c)
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
Example fix
# before (patch hunk targets a directory) *** Update File: src/utils # after *** Update File: src/utils.rs
Defensive patterns
Strategy: validation
Validate before calling
for hunk in hunks {
let p = cwd.as_path().join(hunk.path());
if let Ok(meta) = std::fs::metadata(&p) {
if meta.is_dir() {
return Err(format!("patch target is a directory: {}", p.display()));
}
}
} Try / catch
if let Err(failure) = apply_hunks(&hunks, &cwd, &mut out, &mut err, fs, None).await {
let (err, _) = failure.into_parts();
if let ApplyPatchError::IoError(io) = err {
if io.source().kind() == std::io::ErrorKind::InvalidInput { /* directory target */ }
}
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- approval_policy = "untrusted" is no longer supported; remove
- invalid remote control account id header: {err}
- remote control URL cannot be a base
- {error}
- No files were modified.
AI-assisted analysis of openai/codex@339751715c (2026-08-25).
Data as JSON: /api/errors/e084ac81a1d0a640.
Report an issue: GitHub.