Malformed `[agents]` entry: config/read surfaces misleading "AbsolutePathBuf deserialized without a base path" while other loaders report the real error; config/batchWrite blocked

Open 💬 2 comments Opened Aug 7, 2026 by tsuvic

What version of the Codex App are you using (From "About Codex" dialog)?

ChatGPT desktop 26.803.41515 (bundled codex 0.147.0-alpha.6.5); also verified with standalone CLI 0.146.0

What subscription do you have?

Plus

What platform is your computer?

Darwin 25.5.0 arm64 arm (macOS 26.5.2)

What issue are you seeing?

Related context first: #19257 / #19261 fixed the legitimate case (a relative config_file in [agents.<role>] failing with "AbsolutePathBuf deserialized without a base path"). I verified that fix works in 0.147.0-alpha.6.5. This report is about a different trigger that produces the same misleading message, plus two behavior problems that follow from it.

Trigger: any unknown key under [agents] whose value is a 2-element array. This happened to me when the top-level notify array was accidentally placed inside the [agents] table (a TOML placement mistake — keys after a [table] header belong to that table):

[agents]
enabled = true
default_subagent_model = "gpt-5.6-terra"

notify = ["/path/to/notify-program", "turn-ended"]   # parsed as agents.notify

Unknown [agents] keys are interpreted as agent-role definitions (AgentRoleToml, 3 elements), so ["/path/to/notify-program", "turn-ended"] is parsed as a role whose config_file is the string "turn-ended" — no actual path is involved. For this one file, three different behaviors are observed depending on which loader runs:

  1. config/read (app-server) — the path the desktop UI uses for chat creation, composer submit, and conversation prewarm — returns:

``
invalid configuration: AbsolutePathBuf deserialized without a base path
in
agents
``

This message is misleading (nothing is wrong with any path) and carries no file:line:column. Result: every chat creation fails ("Error creating local task", "[Composer] submit failed").

  1. Startup / reload / CLI loaders report a different, precise error for the same file:

``
config.toml:10:1: invalid length 2, expected struct AgentRoleToml with 3 elements
``

At startup the app degrades gracefully ("Invalid configuration; using defaults" + a configWarning notification with the exact file:line:column range), but config/read hard-fails — inconsistent degradation for the same file within the same process.

  1. config/batchWrite is rejected (configValidationError) while the file is in this state, so the app cannot write any config change. In my incident, changing the model/reasoning effort in the UI failed with "Failed to update model and reasoning effort". Combined with (1), the app can neither be used nor self-repair; recovery requires a manual external edit of config.toml plus an app restart (on restart the app re-serializes config.toml and moves misplaced top-level keys back, which fixed it).

What steps can reproduce the bug?

Deterministic, isolated reproduction (no auth needed):

  1. Create an empty CODEX_HOME dir with this config.toml (any unknown key with a 2-element array under [agents] works):

``toml
[agents]
enabled = true
notify = ["/usr/bin/true", "turn-ended"]
``

  1. CLI (clear error):

``
$ CODEX_HOME=<dir> codex exec hi
Error loading config.toml: invalid length 2, expected struct AgentRoleToml with 3 elements
in
agents
``

  1. app-server (misleading error — what the desktop UI shows):

``
$ CODEX_HOME=<dir> codex app-server # JSON-RPC over stdio
{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"clientInfo":{"name":"Codex Desktop","version":"26.803.41515","title":"Codex Desktop"},"capabilities":{}}}
{"jsonrpc":"2.0","id":9,"method":"config/read","params":{}}
``

→ startup emits configWarning with config.toml:10:1: invalid length 2, expected struct AgentRoleToml with 3 elements (range line 10, cols 1–8), then config/read responds:

``json
{"error":{"code":-32603,"message":"invalid configuration: AbsolutePathBuf deserialized without a base path\nin
agents\n"},"id":9}
``

  1. config/batchWrite against the same file fails with configValidationError (observed in the real incident; any write is rejected until the file is fixed externally).

Incident evidence (verbatim, from the desktop app's electron log under ~/Library/Logs/com.openai.codex/, times UTC):

07:08:08.057 error Request failed error={"code":-32603,"message":"invalid configuration: AbsolutePathBuf deserialized without a base path\nin `agents`\n"} failureReason=invalid_config method=config/read
07:08:08.058 error [Composer] submit failed cwd=~/dev/<project> errorMessage="invalid configuration: AbsolutePathBuf deserialized without a base path\nin `agents`\n"
07:09:00.080 error Request failed error={"code":-32600,"data":{"config_write_error_code":"configValidationError"},"message":"Invalid configuration: AbsolutePathBuf deserialized without a base path\nin `agents`\n"} method=config/batchWrite
07:09:00.081 error Failed to update model and reasoning effort
07:09:33.842 error Error creating local task errorMessage="invalid configuration: AbsolutePathBuf deserialized without a base path\nin `agents`\n"
07:09:51.702 error Request failed error={"code":-32603,"message":"failed to reload config: ~/.codex/config.toml:10:1: invalid length 2, expected struct AgentRoleToml with 3 elements"} method=app/installed

and from app-server tracing (~/.codex/logs_2.sqlite):

WARN codex_app_server::request_processors::account_processor:
failed to reload config, using startup config:
~/.codex/config.toml:10:1: invalid length 2, expected struct AgentRoleToml with 3 elements

What is the expected behavior?

  • One consistent, actionable error for a malformed config across all loaders. The startup loader already produces the right one (with file:line:column); the config/read path should surface that instead of an internal serde-level AbsolutePathBuf message that points at a nonexistent path problem.
  • Consider having config/read degrade the way startup does (return config + warning) instead of hard-failing every chat creation.
  • Consider not holding all config/batchWrite operations hostage to one malformed section — otherwise the app cannot repair the file and the user must edit it externally and restart. (Understood that rewriting an unparsed file risks data loss; even a targeted error message telling the user which file/line to fix would help.)
  • Minor: unknown keys under [agents] that collide with top-level config keys (notify) could be called out by name in the error.

Additional information

  • The AgentsToml/AgentRoleToml schema and the clear invalid length 2 error exist identically in CLI 0.146.0 and 0.147.0-alpha.6.5.
  • Workaround for anyone hitting this: fix the misplaced key (top-level keys must appear before any [section] header) or remove the offending entry; note also that explicit [agents.<role>] registration is optional — *.toml under $CODEX_HOME/agents/ is auto-discovered (per #19257).
  • It could not be determined from logs which actor produced the misplaced notify line (an external tooling session and the app's own computer-use setup both wrote config.toml in the same window). The report is about the app's handling of the resulting file, independent of that question.

View original on GitHub ↗

2 Comments

tsuvic · 21 days ago

Adding a standalone reproduction/verification script. It is self-contained (temp CODEX_HOME only, no auth needed) and asserts all three behaviors: the clear CLI error, the precise configWarning notification, and the misleading config/read error.

Verified today on both codex CLI 0.146.0 and the bundled 0.147.0-alpha.6.5 — all three checks pass on both.

#!/usr/bin/env bash
# Standalone reproduction for openai/codex#37407
#
# Malformed `[agents]` entry (unknown key with a 2-element array) produces:
#   [1] CLI/startup loader : clear error "... invalid length 2, expected struct AgentRoleToml ..."
#   [2] app-server config/read : misleading "AbsolutePathBuf deserialized without a base path in `agents`"
# plus a startup `configWarning` notification carrying the precise file:line:column.
#
# No auth required. Writes nothing outside a temp dir.
# Usage: CODEX_BIN=/path/to/codex ./codex-repro-37407.sh   (defaults to `codex` on PATH)
set -u

BIN="${CODEX_BIN:-codex}"
command -v "$BIN" >/dev/null 2>&1 || { echo "codex binary not found: $BIN"; exit 1; }

WORK="$(mktemp -d "${TMPDIR:-/tmp}/codex-repro-37407.XXXXXX")"
SRV=""
cleanup() {
  exec 3>&- 2>/dev/null
  [ -n "$SRV" ] && kill "$SRV" 2>/dev/null
  rm -rf "$WORK"
}
trap cleanup EXIT

cat > "$WORK/config.toml" <<'EOF'
[agents]
enabled = true
notify = ["/usr/bin/true", "turn-ended"]
EOF

echo "== binary: $BIN ($("$BIN" --version 2>&1 | head -1))"
echo "== CODEX_HOME: $WORK"
echo "== config.toml:"
cat "$WORK/config.toml"
echo

# ---------------------------------------------------------------- [1] CLI loader
echo "== [1] CLI load (codex exec):"
OUT1="$(CODEX_HOME="$WORK" "$BIN" exec hi --skip-git-repo-check 2>&1 | head -5)"
echo "$OUT1"
if printf '%s' "$OUT1" | grep -q "invalid length 2, expected struct AgentRoleToml with 3 elements" \
   && printf '%s' "$OUT1" | grep -q 'in `agents`'; then
  echo "==> [1] PASS: clear AgentRoleToml error"
else
  echo "==> [1] UNEXPECTED: no AgentRoleToml error"
fi
echo

# ------------------------------------------------- [2] app-server config/read path
mkfifo "$WORK/in"
CODEX_HOME="$WORK" "$BIN" app-server < "$WORK/in" > "$WORK/out.log" 2> "$WORK/err.log" &
SRV=$!
exec 3>"$WORK/in"
printf '%s\n' '{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"clientInfo":{"name":"Codex Desktop","version":"26.803.41515","title":"Codex Desktop"},"capabilities":{}}}' >&3
sleep 3
printf '%s\n' '{"jsonrpc":"2.0","id":9,"method":"config/read","params":{}}' >&3
sleep 2
exec 3>&-
sleep 1
kill "$SRV" 2>/dev/null
wait "$SRV" 2>/dev/null
SRV=""

WARN_LINE="$(grep '"configWarning"' "$WORK/out.log" | head -1)"
ERR_LINE="$(grep '"id":9' "$WORK/out.log" | head -1)"

echo "== [2a] startup configWarning notification (precise file:line:column):"
echo "${WARN_LINE:-<none>}"
echo
echo "== [2b] config/read JSON-RPC response (what the desktop UI surfaces):"
echo "${ERR_LINE:-<none>}"
echo

if printf '%s' "$WARN_LINE" | grep -q "invalid length 2, expected struct AgentRoleToml with 3 elements"; then
  echo "==> [2a] PASS: configWarning carries the real error with line/column"
else
  echo "==> [2a] UNEXPECTED: no configWarning with AgentRoleToml error"
fi
if printf '%s' "$ERR_LINE" | grep -q "AbsolutePathBuf deserialized without a base path"; then
  echo "==> [2b] PASS (bug reproduced): config/read returns the misleading AbsolutePathBuf error"
else
  echo "==> [2b] UNEXPECTED: config/read did not return the AbsolutePathBuf error"
fi

Sample output (codex CLI 0.146.0, macOS; identical on 0.147.0-alpha.6.5):

== [1] CLI load (codex exec):
Error loading config.toml: invalid length 2, expected struct AgentRoleToml with 3 elements
in `agents`
==> [1] PASS: clear AgentRoleToml error

== [2a] startup configWarning notification (precise file:line:column):
{"method":"configWarning","params":{"summary":"Invalid configuration; using defaults.","details":"<dir>/config.toml:1:1: invalid length 2, expected struct AgentRoleToml with 3 elements","path":"<dir>/config.toml","range":{"start":{"line":1,"column":1},"end":{"line":1,"column":8}}}}

== [2b] config/read JSON-RPC response (what the desktop UI surfaces):
{"error":{"code":-32603,"message":"invalid configuration: AbsolutePathBuf deserialized without a base path\nin `agents`\n"},"id":9}

==> [2a] PASS: configWarning carries the real error with line/column
==> [2b] PASS (bug reproduced): config/read returns the misleading AbsolutePathBuf error

Note the two messages in [2a] vs [2b] are emitted for the same file within the same process: the startup path knows the exact location (line/column), while config/read — the path the desktop UI depends on — returns the unrelated AbsolutePathBuf message without it.

tsuvic · 9 days ago

Re-verified on 0.148.0 (release binary, macOS arm64) with the standalone repro script above (isolated temp CODEX_HOME, no auth). The loader divergence is unchanged:

For an [agents] table containing an unknown 2-element array entry (notify = ["/usr/bin/true", "turn-ended"]):

  1. CLI loader — clear, actionable:

Error loading config.toml: invalid length 2, expected struct AgentRoleToml with 3 elements in agents``

  1. Startup configWarning notification — carries the same real error with path + range (line 1, columns 1–8).
  2. app-server config/read (the response the desktop UI surfaces) — still the misleading downstream artifact:
{"error":{"code":-32603,"message":"invalid configuration: AbsolutePathBuf deserialized without a base path\nin `agents`\n"},"id":9}

So on 0.148.0 the config/read path still reports the deserialization artifact instead of the real config error that (1) and (2) already produce, and config/batchWrite remains blocked by the same invalid config, leaving the app unable to self-repair the file.