Skip to content

Plugin hooks fail with exit 1 for the remainder of a session after the startup marketplace auto-upgrade replaces the cached plugin version #31383

Description

@Victor-Quqi

What version of Codex CLI is running?

codex-cli 0.142.5

What subscription do you have?

None

Which model were you using?

gpt-5.5

What platform is your computer?

Windows 11 Home (10.0.22631)

What terminal emulator and version are you using (if applicable)?

Windows Terminal + PowerShell 7.6.3

Codex doctor report

Omitted — the report contains no plugin/marketplace lifecycle diagnostics beyond what is described below; specific sections available on request.

What issue are you seeing?

I maintain a plugin installed from a git marketplace that declares SessionStart / UserPromptSubmit / Stop hooks. After new commits land in the marketplace repo, the first Codex session started afterwards reports hook exit 1 on every hook event, for the entire session — without any manual upgrade having been run. Starting another session makes the problem disappear.

Reading the source (main branch; behavior observed on 0.142.5), this looks like a lifecycle race between the startup marketplace auto-upgrade and hook declaration loading:

  1. On startup, maybe_start_plugin_startup_tasks_for_config (codex-rs/core-plugins/src/manager.rs) unconditionally spawns the plugins-marketplace-auto-upgrade thread. When the git marketplace has new commits, it activates the new marketplace root and calls refresh_non_curated_plugin_cache_force_reinstall_detailed, which reinstalls the plugin cache even when the plugin version is unchanged. This part is directly visible in the source, and the auto-upgrade itself is confirmed on my machine: .codex-marketplace-install.json picked up new upstream revisions with no manual action.
  2. The reinstall path in codex-rs/core-plugins/src/store.rs invalidates the previously active cache directory either way: a version bump ends with remove_old_plugin_versions deleting the old version directory (remove_dir_all); an unchanged version replaces the whole plugin cache entry via a backup/rename swap.
  3. Hook commands reference ${PLUGIN_ROOT}, which resolves to a versioned cache path (plugins/cache/<marketplace>/<plugin>/<version>/…). I could not pin down the exact expansion site in the source, but the observed behavior — the already-running session fails on every subsequent hook event while a freshly started session works — suggests the resolved path is captured when the plugin is loaded and not re-resolved for the lifetime of the session.
  4. If that reading is right, the failure sequence is: hooks load early against the old cache path, the background upgrade then deletes or replaces that path, and every later hook invocation runs node <now-gone-path>/scripts/hook.mjs, which exits 1 (ERR_MODULE_NOT_FOUND) until the session ends. The next session resolves the already-upgraded cache and works — matching what I see.

Since the cache is shared, a newly started Codex process should likewise invalidate hooks of other sessions still running. I have not specifically reproduced this cross-process case; it follows from the same mechanism.

Windows note: the rename swap can presumably fail while a hook node process briefly holds file handles. Possibly related, one upgrade attempt left a stale marketplace-upgrade-* staging directory behind under .tmp/marketplaces/.staging/.

What steps can reproduce the bug?

Observed with a real plugin; a minimal setup should look like:

  1. Create a git marketplace with one plugin whose hook command references ${PLUGIN_ROOT}, e.g. node "${PLUGIN_ROOT}/scripts/hook.mjs" (script body irrelevant; exiting 0 is enough).
  2. Add the marketplace and install the plugin.
  3. Push a commit to the marketplace repo. Per the analysis above, bumping the plugin version should make the failure deterministic; content-only changes only expose the shorter swap window.
  4. Start a new Codex TUI session and trigger hook events.
  5. Hook invocations fail with exit 1 for the rest of the session; the next session works again.

What is the expected behavior?

A marketplace auto-upgrade should not invalidate hook commands of running sessions. Possible directions:

  • re-resolve / reload hook declarations after the startup auto-upgrade completes (at least in the process that performed it), or
  • resolve ${PLUGIN_ROOT} lazily at hook-execution time against the currently active version, or
  • keep superseded version directories until no running session references them (grace period / in-use tracking) instead of deleting them right after activation.

Additional information

Timeline on my machine consistent with the analysis: hooks in a running session began failing a few hours after an upstream push, in the same window as an auto-upgrade attempt (the one that left the stale staging directory); the install metadata showed the new revision although no manual upgrade was run. Source references are against current main — happy to re-verify against a specific tag if useful.

Metadata

Metadata

Assignees

No one assigned

    Labels

    CLIIssues related to the Codex CLIbugSomething isn't workinghooksIssues related to event hooksskillsIssues related to skillswindows-osIssues related to Codex on Windows systems

    Type

    No type

    Fields

    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