{"record":{"id":"e1f6743315501ec7","repo":"openai/codex","slug":"invalidinput-e1f674","errorCode":"InvalidInput","errorMessage":"permissions profile requests filesystem writes outside the workspace root, which is not supported until the runtime enforces FileSystemSandboxPolicy directly","messagePattern":"permissions profile requests filesystem writes outside the workspace root, which is not supported until the runtime enforces FileSystemSandboxPolicy directly","errorType":"exception","errorClass":"io::Error","httpStatus":null,"severity":"error","filePath":"codex-rs/protocol/src/permissions.rs","lineNumber":1471,"sourceCode":"                    });\n                }\n\n                if workspace_root_writable {\n                    SandboxPolicy::WorkspaceWrite {\n                        writable_roots: dedup_absolute_paths(\n                            writable_roots,\n                            /*normalize_effective_paths*/ false,\n                        ),\n                        network_access: network_policy.is_enabled(),\n                        exclude_tmpdir_env_var: !tmpdir_writable,\n                        exclude_slash_tmp: !slash_tmp_writable,\n                    }\n                } else if unbridgeable_root_write\n                    || !writable_roots.is_empty()\n                    || tmpdir_writable\n                    || (cfg!(unix) && slash_tmp_writable)\n                {\n                    return Err(io::Error::new(\n                        io::ErrorKind::InvalidInput,\n                        \"permissions profile requests filesystem writes outside the workspace root, which is not supported until the runtime enforces FileSystemSandboxPolicy directly\",\n                    ));\n                } else {\n                    SandboxPolicy::ReadOnly {\n                        network_access: network_policy.is_enabled(),\n                    }\n                }\n            }\n        })\n    }\n\n    fn resolved_entries_with_cwd(&self, cwd: &Path) -> Vec<ResolvedFileSystemEntry> {\n        let cwd_absolute = AbsolutePathBuf::from_absolute_path(cwd).ok();\n        self.entries\n            .iter()\n            .filter_map(|entry| {\n                resolve_entry_path(&entry.path, cwd_absolute.as_ref()).map(|path| {","sourceCodeStart":1453,"sourceCodeEnd":1489,"githubUrl":"https://github.com/openai/codex/blob/339751715c64496cb86246bfb3935f40e309dd3d/codex-rs/protocol/src/permissions.rs#L1453-L1489","documentation":"Thrown while converting a restricted FileSystemSandbox permissions profile into the legacy SandboxPolicy enum. The legacy policy can only express ReadOnly, WorkspaceWrite (writable cwd plus extra roots), or full access; if a profile grants write access outside the workspace root while the workspace root itself is not writable, no legacy policy can represent that shape, so the conversion fails fast with ErrorKind::InvalidInput instead of silently weakening the sandbox.","triggerScenarios":"Converting a FileSystemSandboxKind::Restricted profile whose entries grant Write to FileSystemSpecialPath::Root, to any absolute path other than the cwd, to Tmpdir, or (on unix) to SlashTmp - while no entry grants write on the cwd / ProjectRoots, so workspace_root_writable stays false.","commonSituations":"A permissions profile that grants write to a scratch or temp directory but leaves the project itself read-only; older profiles written when the runtime enforced FileSystemSandboxPolicy directly being fed through the legacy conversion path; hand-edited YAML with a stray out-of-root write entry.","solutions":["Add a write grant for the workspace root (write on ProjectRoots or on the cwd path) so the profile maps to WorkspaceWrite; extra writable roots are then permitted","Remove the out-of-root write grants (Root, other absolute paths, Tmpdir, SlashTmp) so the profile maps to ReadOnly","If whole-disk write is truly intended, use an unrestricted / full-disk-write profile instead of Restricted","If restricted-mode writes outside the root are required, consume the profile's FileSystemSandboxPolicy directly rather than converting to legacy SandboxPolicy"],"exampleFix":"// before: restricted profile, no project-root write\n- path: { special: tmpdir }\n  access: write\n// after: add project-root write so the profile maps to WorkspaceWrite\n- path: { special: project_roots }\n  access: write\n- path: { special: tmpdir }\n  access: write","handlingStrategy":"validation","validationCode":"let cwd_abs = AbsolutePathBuf::from_absolute_path(cwd).ok();\nlet mut root_writable = false;\nlet mut outside_write = false;\nfor e in &profile.entries {\n    if !e.access.can_write() { continue; }\n    match resolve_entry_path(&e.path, cwd_abs.as_ref()) {\n        Some(p) if cwd_abs.as_ref() == Some(&p) => root_writable = true,\n        Some(_) => outside_write = true,\n        None => if let FileSystemPath::Special { value } = &e.path {\n            if matches!(value, FileSystemSpecialPath::Root | FileSystemSpecialPath::Tmpdir | FileSystemSpecialPath::SlashTmp) { outside_write = true; }\n        },\n    }\n}\nif !root_writable && outside_write { return Err(invalid_profile()); }","typeGuard":null,"tryCatchPattern":"let policy = match profile.try_into() {\n    Ok(p) => p,\n    Err(e) if e.kind() == std::io::ErrorKind::InvalidInput => {\n        return Err(anyhow::anyhow!(\"invalid permissions profile: {e}\"))\n    }\n    Err(e) => return Err(e.into()),\n};","preventionTips":["Always pair out-of-root write grants with a workspace-root write grant","Convert representative profiles in unit tests / CI to catch invalid shapes early","Surface InvalidInput from this conversion as a user-facing configuration error, not a runtime fault"],"tags":["rust","sandbox","permissions","config-validation"],"backgroundTag":"sandbox-policy-unsupported","analyzedSha":"339751715c64496cb86246bfb3935f40e309dd3d","analyzedAt":"2026-08-25T05:35:09.876Z","schemaVersion":2},"datasetVersion":"2026-08-25T06:17:31.827Z"}