Codex CLI: plugin marketplace sync feedback loop pegs CPU at 100%, unkillable by SIGTERM
Summary
A malformed marketplace.json (with "source": "./") causes the plugin marketplace
sync subsystem to enter a tight retry loop. The loop is fast enough to starve the
event loop, after which the process pegs one core at 100% indefinitely and ignores
SIGTERM (only SIGKILL kills it). Log output stops several minutes before the user
notices, so there is no in-product signal that anything is wrong.
Symptoms
- One Codex process at 100% CPU on a single core for 35+ minutes
- Unresponsive to
kill <pid>(SIGTERM) — requiredkill -9 - No new entries in
~/.codex/log/codex-tui.logfor the last ~18 minutes before kill,
despite the process being fully active
Root cause (from logs)
The last log entries before the silent loop show this sequence repeating ~every 3 seconds:
codex_core_skills::manager: skills cache cleared (1 entries)
codex_core_plugins::marketplace: skipping marketplace plugin that failed to resolve
path=~/.codex/.tmp/marketplaces/cloudflare/.claude-plugin/marketplace.json
plugin="cloudflare"
error=invalid marketplace file: local plugin source path must not be empty
codex_core_plugins::remote::remote_installed_plugin_sync: completed remote
installed plugin bundle sync ...
grep -c against the log shows 961 occurrences of these two messages before
logging fell behind / stopped.
The marketplace file in question is well-formed JSON; the offending field is:
{
"plugins": [
{ "name": "cloudflare", "source": "./", ... }
]
}
The resolver normalizes "./" to empty and rejects it. But the sync logic then
re-stages the marketplace bundle (~/.codex/.tmp/marketplaces/.staging had 78
recently-touched entries and 76 MB at time of kill), which appears to re-trigger
the watcher, which re-runs sync, which fails again — feedback loop.
Distinct bugs implied here
- Config error → unbounded retries with no backoff — a single un-resolvable
plugin shouldn't be re-tried 961+ times per session.
- File-watcher feedback loop — staging into a directory being watched re-fires
the watcher.
- Event-loop starvation in Rust core —
@openai/codexNode wrapper became
unresponsive to SIGTERM because the underlying Rust task held the runtime.
- Silent failure — log flushing fell behind the loop, so the last ~18 min of
the failure had zero diagnostic output.
Repro (theoretical, not re-tested)
Place any plugin in a marketplace where source: "./" (or any value that
normalizes to empty). Launch Codex. The retry loop should begin during startup
plugin sync.
Workaround
Stop Codex, then:
rm -rf ~/.codex/.tmp/marketplaces/.staging ~/.codex/.tmp/marketplaces/marketplace-backup-*
Editing the offending marketplace.json's "source" to an absolute path also
prevents the loop.
Environment
- macOS (Darwin 25.4.0, Apple Silicon)
- Codex (
@openai/codex), version per~/.codex/version.json:0.133.0 - Node runtime bundled with Codex