openai/codex · warning · io::Error
generated image directory is not a real directory
Error message
generated image directory is not a real directory
What it means
After creating the parent of <cwd>/generated_images, save_image_generation_result stats it: if the metadata is a symlink or not a directory, it returns PermissionDenied. This is a deliberate security guard — full-access executor contexts cannot rely on sandboxing to stop symlinked output directories, and a write through a symlinked generated_images would escape the workspace.
Source
Thrown at codex-rs/ext/image-generation/src/tool.rs:346
environment
.file_system
.create_directory(
&parent_uri,
CreateDirectoryOptions {
recursive: true,
follow_symlinks: true,
},
sandbox,
)
.await?;
// Full-access executor contexts do not prevent symlinked output directories.
let metadata = environment
.file_system
.get_metadata(&parent_uri, Default::default(), sandbox)
.await?;
if metadata.is_symlink || !metadata.is_directory {
return Err(io::Error::new(
io::ErrorKind::PermissionDenied,
"generated image directory is not a real directory",
));
}
}
// Existing destination hardlinks could otherwise overwrite files outside the workspace.
let path_uri = PathUri::from_abs_path(&path);
match environment
.file_system
.get_metadata(&path_uri, Default::default(), sandbox)
.await
{
Ok(_) => {
return Err(io::Error::new(
io::ErrorKind::AlreadyExists,
"generated image destination already exists",
));View on GitHub (pinned to 339751715c)
Solutions
- Replace the generated_images symlink with a real directory (remove the link, then mkdir).
- Delete any regular file named generated_images in the working directory.
- If linking is needed for artifact collection, configure save_root and link outside cwd instead.
Example fix
# before generated_images -> /mnt/shared/artifacts # after rm generated_images && mkdir generated_images
Defensive patterns
Strategy: validation
Validate before calling
// Before running executor tool calls in a workspace
let dir = environment.cwd.join("generated_images");
if let Ok(md) = std::fs::symlink_metadata(&dir) {
if md.is_symlink() || !md.is_dir() {
std::fs::remove_file(&dir).ok();
std::fs::create_dir_all(&dir)?;
}
} Type guard
fn is_real_directory(md: &std::fs::Metadata) -> bool {
!md.is_symlink() && md.is_dir()
} Prevention
- Never create generated_images as a symlink; collect artifacts outside cwd instead.
- Workspace setup scripts should mkdir -p real output directories.
- Remember this guard exists because full-access executors cannot rely on sandboxing.
When it happens
Trigger: An executor tool call runs with environment.cwd containing a generated_images symlink (or a regular file of that name), so the created parent resolves outside the workspace or is not a directory.
Common situations: Developer pre-created generated_images as a symlink to a shared artifact folder; CI workspaces with linked output directories; a file named generated_images already exists.
Related errors
- generated image exceeds the executor file size limit
- generated image destination already exists
- PermissionDenied
- externally enforced filesystem permissions cannot be interse
- Unsupported platform: ${platform} (${arch})
AI-assisted analysis of openai/codex@339751715c (2026-08-25).
Data as JSON: /api/errors/29f93424834e282e.
Report an issue: GitHub.