Skip to content

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

@nomosnomos

Description

@nomosnomos

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.
  2. File-watcher feedback loop — staging into a directory being watched re-fires
    the watcher.
  3. Event-loop starvation in Rust core@openai/codex Node wrapper became
    unresponsive to SIGTERM because the underlying Rust task held the runtime.
  4. 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

Metadata

Metadata

Assignees

No one assigned

    Labels

    CLIIssues related to the Codex CLIbugSomething isn't workingperformanceskillsIssues related to skills

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions