openai/codex · critical

plugin cache root should be absolute: {err}

Error message

plugin cache root should be absolute: {err}

What it means

PluginStore::new panics (unwrap_or_else(panic!)) when try_new fails. try_new runs AbsolutePathBuf::from_absolute_path_checked over codex_home and joined subdirectories (plugin cache/data roots); from_absolute_path_checked rejects any non-absolute path, so the panic fires when the supplied codex_home PathBuf is relative (e.g. "codex-home", ".codex", or empty). It is a hard process abort by design: callers are expected to hand in an absolute CODEX_HOME.

Source

Thrown at codex-rs/core-plugins/src/store.rs:104

            return Err(PluginStoreError::Invalid(
                "invalid remote plugin install metadata: remote plugin id must not be blank"
                    .to_string(),
            ));
        }
        Ok(Some(remote_plugin_id.to_string()))
    }
}

#[derive(Clone, Copy)]
enum InstallManifest<'a> {
    OnDisk,
    Fallback(&'a str),
}

impl PluginStore {
    pub fn new(codex_home: PathBuf) -> Self {
        Self::try_new(codex_home)
            .unwrap_or_else(|err| panic!("plugin cache root should be absolute: {err}"))
    }

    pub fn try_new(codex_home: PathBuf) -> Result<Self, PluginStoreError> {
        let root = AbsolutePathBuf::from_absolute_path_checked(codex_home.join(PLUGINS_CACHE_DIR))
            .map_err(|err| PluginStoreError::io("failed to resolve plugin cache root", err))?;
        let data_root =
            AbsolutePathBuf::from_absolute_path_checked(codex_home.join(PLUGINS_DATA_DIR))
                .map_err(|err| PluginStoreError::io("failed to resolve plugin data root", err))?;
        let codex_home = AbsolutePathBuf::from_absolute_path_checked(codex_home)
            .map_err(|err| PluginStoreError::io("failed to resolve Codex home", err))?;

        Ok(Self {
            codex_home,
            root,
            data_root,
        })
    }

View on GitHub (pinned to 339751715c)

Solutions

  1. Canonicalize before constructing: std::fs::create_dir_all(&home).ok(); let home = std::fs::canonicalize(&home)?; then PluginStore::new(home)
  2. Prefer PluginStore::try_new(...) when a graceful Result is needed instead of a panic
  3. Validate early: assert/return an error if !codex_home.is_absolute() at the boundary where the value enters (env var / CLI flag parsing)
  4. Normalize relative values by joining onto the current dir or the user home before use

Example fix

// before
let store = PluginStore::new(PathBuf::from(".codex")); // panics: plugin cache root should be absolute

// after
let home = std::env::current_dir()?.join(".codex");
let store = PluginStore::try_new(home)?; // or PluginStore::new() with a proven-absolute path
Defensive patterns

Strategy: validation

Validate before calling

// Before constructing the store:
let home = if codex_home.is_absolute() {
    codex_home
} else {
    std::env::current_dir()?.join(codex_home)
};
let store = PluginStore::try_new(home)?; // graceful instead of panic

Type guard

fn is_absolute_codex_home(p: &std::path::Path) -> bool {
    p.is_absolute()
}

Try / catch

// Prefer the Result API; if you must keep new(), catch_unwind only at a hard boundary:
let store = std::panic::catch_unwind(|| PluginStore::new(codex_home))
    .map_err(|p| downcast_panic_message(p))?; // best: switch to try_new

Prevention

When it happens

Trigger: Calling PluginStore::new(PathBuf::from(<relative path>)) — any codex_home lacking a root component (no leading '/' on Unix or drive prefix on Windows); also a default-constructed/empty PathBuf.

Common situations: Tests constructing the store with a tempdir-relative path instead of its absolute form; reading CODEX_HOME from an env var that happens to be relative; refactors that pass a config string where an absolute path was expected; CLI invocations with a relative --codex-home flag.

Related errors


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