Codex CLI: plugin marketplace sync feedback loop pegs CPU at 100%, unkillable by SIGTERM

Resolved 💬 0 comments Opened May 23, 2026 by nomosnomos Closed May 26, 2026

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) — required kill -9
  • No new entries in ~/.codex/log/codex-tui.log for 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

  1. Config error → unbounded retries with no backoff — a single un-resolvable

plugin shouldn't be re-tried 961+ times per session.

  1. File-watcher feedback loop — staging into a directory being watched re-fires

the watcher.

  1. Event-loop starvation in Rust core@openai/codex Node wrapper became

unresponsive to SIGTERM because the underlying Rust task held the runtime.

  1. 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

View original on GitHub ↗