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

  1. Replace the generated_images symlink with a real directory (remove the link, then mkdir).
  2. Delete any regular file named generated_images in the working directory.
  3. 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

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


AI-assisted analysis of openai/codex@339751715c (2026-08-25). Data as JSON: /api/errors/29f93424834e282e. Report an issue: GitHub.