openai/codex · error · PermissionProfileResolutionError

permissions profile `{profile_name}` cannot extend unsupport

Error message

permissions profile `{profile_name}` cannot extend unsupported built-in profile `{parent_profile_name}`

What it means

Profile names starting with ':' are reserved for built-in profiles supplied by the loader's parent_profile closure. When extends targets such a colon-prefixed name that the installed version does not provide, resolve_profile reports UnsupportedBuiltInParent instead of the generic undefined-parent error. It separates 'you extended a built-in we no longer know' from ordinary typos.

Source

Thrown at codex-rs/config/src/permissions_toml.rs:132

    pub description: Option<String>,
    pub extends: Option<String>,
    pub workspace_roots: Option<WorkspaceRootsToml>,
    pub filesystem: Option<FilesystemPermissionsToml>,
    pub network: Option<NetworkToml>,
}

#[derive(Debug, Clone, PartialEq, Eq, Error)]
pub enum PermissionProfileResolutionError {
    #[error("default_permissions refers to undefined profile `{profile_name}`")]
    UndefinedProfile { profile_name: String },
    #[error(
        "permissions profile `{profile_name}` extends undefined profile `{parent_profile_name}`"
    )]
    UndefinedParent {
        profile_name: String,
        parent_profile_name: String,
    },
    #[error(
        "permissions profile `{profile_name}` cannot extend unsupported built-in profile `{parent_profile_name}`"
    )]
    UnsupportedBuiltInParent {
        profile_name: String,
        parent_profile_name: String,
    },
    #[error(
        "permissions profile inheritance cycle detected: {}",
        cycle.join(" -> ")
    )]
    Cycle { cycle: Vec<String> },
    #[error("failed to serialize permissions profile while resolving inheritance: {source}")]
    SerializeProfileToml {
        #[source]
        source: toml::ser::Error,
    },
    #[error(
        "failed to deserialize merged permissions profile while resolving inheritance: {source}"

View on GitHub (pinned to 339751715c)

Solutions

  1. Use the built-in name exactly as documented for the installed version (check spelling: hyphens vs underscores)
  2. If you meant a custom profile, drop the leading ':' and extend a profile defined in the permissions table
  3. If the built-in disappeared in an upgrade, pin the working version or replace it with an explicit profile definition

Example fix

# before — misspelled built-in
[permissions.safe]
extends = ":read_only"

# after — exact built-in name for the installed version
[permissions.safe]
extends = ":read-only"
Defensive patterns

Strategy: validation

Validate before calling

// The caller controls which built-ins it passes to resolve_profile; validate
// colon-prefixed extends targets against that same list up front.
const SUPPORTED_BUILTINS: &[&str] = &[
    /* exact names from the installed version's docs, ':' prefix included */
];

fn builtin_parents_are_supported(permissions: &codex_config::PermissionsToml) -> Result<(), String> {
    for (name, profile) in &permissions.entries {
        if let Some(parent) = profile.extends.as_deref()
            && parent.starts_with(':')
            && !SUPPORTED_BUILTINS.contains(&parent)
        {
            return Err(format!("`{name}` extends unsupported built-in `{parent}`"));
        }
    }
    Ok(())
}

Type guard

// ':'-prefixed names claim the built-in namespace; check them against the
// list you will hand to resolve_profile's parent_profile closure.
fn is_supported_builtin(parent: &str, supported: &[&str]) -> bool {
    !parent.starts_with(':') || supported.contains(&parent)
}

Try / catch

match permissions.resolve_profile(name, builtin_lookup) {
    Err(PermissionProfileResolutionError::UnsupportedBuiltInParent { profile_name, parent_profile_name }) => {
        // `parent_profile_name` is ':'-prefixed but unknown: fix its spelling
        // to the documented built-in, or drop the ':' and extend a defined profile.
    }
    Err(e) => return Err(e.into()),
    Ok(profile) => { /* ... */ }
}

Prevention

When it happens

Trigger: `[permissions.x] extends = ":read_only"` when the built-in is spelled differently (e.g. ':read-only') or was removed/renamed in this codex version — the closure returns None for the name and the ':' prefix selects this variant.

Common situations: Underscore vs hyphen spelling mistakes; examples copied from a different codex release; naming a custom profile with a leading ':' (reserved namespace).

Related errors


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