Summary
When ~/.codex/config.toml contains top-level [agents.<role>] tables with a relative config_file, Codex rejects the whole config with:
Invalid configuration: AbsolutePathBuf deserialized without a base path
in `agents`
This manifests as:
- Desktop app (Windows): "Failed to update model setting / 無法更新模型設定" when switching models in the UI — save aborts because the running config re-deserialize fails.
- CLI: fails to start at all.
Root cause
agents_toml_from_layer() in codex-rs/core/src/config/agent_roles.rs deserializes the agents table from TomlValue without wrapping the call in an AbsolutePathBufGuard:
fn agents_toml_from_layer(layer_toml: &TomlValue) -> std::io::Result<Option<AgentsToml>> {
let Some(agents_toml) = layer_toml.get("agents") else { return Ok(None); };
agents_toml.clone().try_into().map(Some).map_err(...)
}
Compare with parse_agent_role_file_contents(), which correctly sets let _guard = AbsolutePathBufGuard::new(config_base_dir); before deserialization.
Because of the missing guard, AgentRoleToml.config_file: Option<AbsolutePathBuf> fails the "has base path OR is absolute" check in AbsolutePathBuf::deserialize(), even though the field's doc comment says:
Relative paths are resolved relative to the config.toml that defines them.
Reproduction
# ~/.codex/config.toml
[agents.my-role]
description = "x"
config_file = "agents/my-role.toml" # relative — fails
Run codex or open Desktop → error above.
Workarounds (for affected users)
- Rewrite
config_file as absolute path, using TOML literal strings to avoid backslash escapes:
config_file = 'C:\Users\you\.codex\agents\my-role.toml'
- Or: delete the
[agents.<role>] blocks entirely — Codex auto-discovers *.toml under $CODEX_HOME/agents/ via discover_agent_roles_in_dir, so these explicit blocks are redundant.
Suggested fix
Set AbsolutePathBufGuard::new(<config.toml's dir>) before the try_into() in agents_toml_from_layer, matching parse_agent_role_file_contents.
Impact on ecosystem installers
The get-shit-done (GSD) installer writes 18 [agents.gsd-*] blocks with relative config_file = "agents/gsd-*.toml" paths, breaking every user who installs GSD on current Codex. Fixing upstream removes the papercut for all such installers.
Environment
- OS: Windows 11
- Codex CLI: 0.124.0 (
npm i -g @openai/codex)
- Codex Desktop (Windows): model switching UI
Summary
When
~/.codex/config.tomlcontains top-level[agents.<role>]tables with a relativeconfig_file, Codex rejects the whole config with:This manifests as:
Root cause
agents_toml_from_layer()incodex-rs/core/src/config/agent_roles.rsdeserializes theagentstable fromTomlValuewithout wrapping the call in anAbsolutePathBufGuard:Compare with
parse_agent_role_file_contents(), which correctly setslet _guard = AbsolutePathBufGuard::new(config_base_dir);before deserialization.Because of the missing guard,
AgentRoleToml.config_file: Option<AbsolutePathBuf>fails the "has base path OR is absolute" check inAbsolutePathBuf::deserialize(), even though the field's doc comment says:Reproduction
Run
codexor open Desktop → error above.Workarounds (for affected users)
config_fileas absolute path, using TOML literal strings to avoid backslash escapes:[agents.<role>]blocks entirely — Codex auto-discovers*.tomlunder$CODEX_HOME/agents/viadiscover_agent_roles_in_dir, so these explicit blocks are redundant.Suggested fix
Set
AbsolutePathBufGuard::new(<config.toml's dir>)before thetry_into()inagents_toml_from_layer, matchingparse_agent_role_file_contents.Impact on ecosystem installers
The
get-shit-done(GSD) installer writes 18[agents.gsd-*]blocks with relativeconfig_file = "agents/gsd-*.toml"paths, breaking every user who installs GSD on current Codex. Fixing upstream removes the papercut for all such installers.Environment
npm i -g @openai/codex)