{"record":{"id":"29f93424834e282e","repo":"openai/codex","slug":"generated-image-directory-is-not-a-real-directory","errorCode":null,"errorMessage":"generated image directory is not a real directory","messagePattern":"generated image directory is not a real directory","errorType":"exception","errorClass":"io::Error","httpStatus":null,"severity":"warning","filePath":"codex-rs/ext/image-generation/src/tool.rs","lineNumber":346,"sourceCode":"                    environment\n                        .file_system\n                        .create_directory(\n                            &parent_uri,\n                            CreateDirectoryOptions {\n                                recursive: true,\n                                follow_symlinks: true,\n                            },\n                            sandbox,\n                        )\n                        .await?;\n\n                    // Full-access executor contexts do not prevent symlinked output directories.\n                    let metadata = environment\n                        .file_system\n                        .get_metadata(&parent_uri, Default::default(), sandbox)\n                        .await?;\n                    if metadata.is_symlink || !metadata.is_directory {\n                        return Err(io::Error::new(\n                            io::ErrorKind::PermissionDenied,\n                            \"generated image directory is not a real directory\",\n                        ));\n                    }\n                }\n\n                // Existing destination hardlinks could otherwise overwrite files outside the workspace.\n                let path_uri = PathUri::from_abs_path(&path);\n                match environment\n                    .file_system\n                    .get_metadata(&path_uri, Default::default(), sandbox)\n                    .await\n                {\n                    Ok(_) => {\n                        return Err(io::Error::new(\n                            io::ErrorKind::AlreadyExists,\n                            \"generated image destination already exists\",\n                        ));","sourceCodeStart":328,"sourceCodeEnd":364,"githubUrl":"https://github.com/openai/codex/blob/339751715c64496cb86246bfb3935f40e309dd3d/codex-rs/ext/image-generation/src/tool.rs#L328-L364","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"# before\ngenerated_images -> /mnt/shared/artifacts\n\n# after\nrm generated_images && mkdir generated_images","handlingStrategy":"validation","validationCode":"// Before running executor tool calls in a workspace\nlet dir = environment.cwd.join(\"generated_images\");\nif let Ok(md) = std::fs::symlink_metadata(&dir) {\n    if md.is_symlink() || !md.is_dir() {\n        std::fs::remove_file(&dir).ok();\n        std::fs::create_dir_all(&dir)?;\n    }\n}","typeGuard":"fn is_real_directory(md: &std::fs::Metadata) -> bool {\n    !md.is_symlink() && md.is_dir()\n}","tryCatchPattern":null,"preventionTips":["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."],"tags":["rust","image-generation","symlink","security","executor"],"backgroundTag":"symlink-escape-blocked","analyzedSha":"339751715c64496cb86246bfb3935f40e309dd3d","analyzedAt":"2026-08-25T05:35:09.876Z","schemaVersion":2},"datasetVersion":"2026-08-25T06:17:31.827Z"}