openai/codex · error · io::Error
InvalidData
InvalidData
Error message
Managed config file {} has no parent directory What it means
Thrown by merge_managed_config_for_discovery while overlaying the managed-config layer for project-root/trust discovery. The loader resolves relative paths inside the managed config against the config file's parent directory (resolve_relative_paths_in_config_toml), and Path::parent() only returns None when the path is empty or the filesystem root itself. In practice this InvalidData guard means the managed config file path degenerated to '/' (or a bare filename) instead of a real file like /etc/codex/managed_config.toml.
Source
Thrown at codex-rs/config/src/loader/project_discovery.rs:20
use super::layer_io::LoadedConfigLayers;
use super::resolve_relative_paths_in_config_toml;
use crate::merge_toml_values;
use std::io;
use std::path::Path;
use toml::Value as TomlValue;
/// Overlay the already-read managed sources at their normal precedence: file,
/// then MDM. Resolve paths as the final loader does, without changing the raw
/// layers or reading either source again.
pub(super) fn merge_managed_config_for_discovery(
discovery_config: &mut TomlValue,
loaded: &LoadedConfigLayers,
codex_home: &Path,
) -> io::Result<()> {
if let Some(config) = &loaded.managed_config {
let base_dir = config.file.as_path().parent().ok_or_else(|| {
io::Error::new(
io::ErrorKind::InvalidData,
format!(
"Managed config file {} has no parent directory",
config.file.as_path().display()
),
)
})?;
let resolved =
resolve_relative_paths_in_config_toml(config.managed_config.clone(), base_dir)?;
merge_toml_values(discovery_config, &resolved);
}
if let Some(config) = &loaded.managed_config_from_mdm {
let resolved =
resolve_relative_paths_in_config_toml(config.managed_config.clone(), codex_home)?;
merge_toml_values(discovery_config, &resolved);
}
Ok(())
}View on GitHub (pinned to 339751715c)
Solutions
- Point managed_config_path at a concrete file inside a directory, e.g. /etc/codex/managed_config.toml or <tmpdir>/managed_config.toml — never '/', a directory, or a bare file name
- When building the path programmatically, assert the base directory is non-empty and not '/' before joining the file name
- If you intended no managed config, remove the file or the override — a missing managed config is tolerated (layer skipped); only a parent-less path is fatal
Example fix
// before: override degenerates to the filesystem root
overrides.managed_config_path = Some(PathBuf::from("/"));
// after: a real file under a directory
overrides.managed_config_path = Some(PathBuf::from("/etc/codex/managed_config.toml")); Defensive patterns
Strategy: validation
Validate before calling
// Run before building LoaderOverrides / loading config.
use std::path::Path;
fn managed_config_path_is_usable(path: &Path) -> bool {
// Path::parent() is None exactly for "" and "/" — the cases the loader rejects.
path.is_absolute() && path.parent().is_some()
}
if let Some(p) = &overrides.managed_config_path {
assert!(managed_config_path_is_usable(p),
"managed config path must be an absolute file path, got {}", p.display());
} Try / catch
match merge_managed_config_for_discovery(&mut discovery_config, &loaded, codex_home) {
Err(e) if e.kind() == io::ErrorKind::InvalidData
&& e.to_string().contains("no parent directory") => {
// The managed config path is '/' or empty — fix the override and reload.
}
result => result?,
} Prevention
- Never set the managed-config override to a directory, '/', or an empty string — always a concrete .toml file path
- Assert base directories are non-empty before joining file names when constructing config paths from variables
- Remember NotFound on the managed config file is fine (layer skipped); only a parent-less path is an error
When it happens
Trigger: The managed config path (LoaderOverrides.managed_config_path override, or the default /etc/codex/managed_config.toml on Unix and CODEX_HOME/managed_config.toml on Windows) resolves to exactly '/' (or an empty/bare filename), that path exists and parses as TOML, and merge_managed_config_for_discovery runs during discovery. Any deeper absolute path has a parent directory and never triggers this.
Common situations: Test fixtures that join a file name onto a base-dir variable that is empty or '/' so the path collapses to a root; scripts building the override from an env var that expands to '/'; CI containers where the config-dir variable is set but the file name is empty. Users on the default path cannot hit it.
Related errors
- Managed config file {} has no parent directory
- Config file {} has no parent directory
- approval_policy = "untrusted" is no longer supported; remove
- remote control URL cannot be a base
- InvalidInput
AI-assisted analysis of openai/codex@339751715c (2026-08-25).
Data as JSON: /api/errors/12b19217b566506e.
Report an issue: GitHub.