Skip to content

[Bug]: a dangling Codex marketplace registration breaks install, uninstall, and refresh #968

Description

@bbednarski9

Affected area

Plugins

Current behavior

When a Codex plugin marketplace is still registered with the host but its marketplace root no longer exists on disk, every Relay plugin command fails — including the --force recovery path the error messages point users toward.

codex plugin list refuses to run while any configured marketplace snapshot fails to load:

installer error: $ /path/to/codex plugin list failed with exit code 1: Error: failed to load configured marketplace snapshot(s):
- `nemo-relay-local` at .../codex-marketplace: marketplace root does not contain a supported manifest

Relay surfaces the host CLI's failure verbatim. The probe is codex_plugin_registered / codex_marketplace_registered in crates/cli/src/installation/marketplace/host.rs, both of which call run_capture_command, which converts any non-zero exit into an error (host.rs:395). Because host_registration_report runs early in the install/uninstall paths, the command dies before any install-state logic is reached.

Confirmed affected: nemo-relay install codex, nemo-relay install codex --force, nemo-relay uninstall codex, nemo-relay integrations refresh.

This is distinct from #963. That issue covers the case where the marketplace root and the host registration are both gone, which is fixed by #965. This issue is the case where only the root is deleted and the registration survives — which is arguably the more common way users get here, since deleting the visible codex-marketplace/ directory is the intuitive "clear it out and reinstall" move and does not unregister anything.

Expected behavior

A dangling marketplace registration should not brick the tooling. At minimum, Relay should report an actionable error naming the stale registration and the exact remediation, rather than propagating a host CLI stack trace. Ideally nemo-relay install codex --force should recover on its own, since it is what every error message recommends.

Steps to reproduce

export CODEX_HOME=/tmp/relay-repro/codex-home
mkdir -p /tmp/relay-repro/{codex-home,plugins}

nemo-relay install codex --install-dir /tmp/relay-repro/plugins   # succeeds

# The intuitive "clear it out" action: delete the tree, leave the registration.
rm -rf /tmp/relay-repro/plugins/codex-marketplace

nemo-relay install codex --install-dir /tmp/relay-repro/plugins --force   # fails
nemo-relay uninstall codex --install-dir /tmp/relay-repro/plugins         # fails
nemo-relay integrations refresh --install-dir /tmp/relay-repro/plugins    # fails

Current workaround — unregister by hand, after which #965's fix takes over and everything recovers:

codex plugin remove nemo-relay-plugin@nemo-relay-local
codex plugin marketplace remove nemo-relay-local
nemo-relay install codex --install-dir /tmp/relay-repro/plugins --force

Environment

Impact

Affects any Codex user who removes the marketplace directory without unregistering first. There is a workaround (the manual codex plugin remove sequence above), but it is not discoverable from the error, which points at codex plugin list rather than at the stale registration.

Note that #965 does not regress this — the pre-#965 binary produces the identical failure. It simply does not cover it.

Notes on a fix

Two layers, and the second carries a design decision worth discussing before implementation.

1. Tolerant probe (safe, self-contained). Don't let a dangling snapshot abort the registration probe. When codex plugin list fails and stderr names nemo-relay-local as an unloadable snapshot, that failure is itself evidence the marketplace is registered but broken, so the report can be answered from it. This alone turns the confusing host stack trace into an actionable Relay error.

2. Making --force actually recover (needs a decision). The tolerant probe alone is likely not sufficient. Reporting host_marketplace_registered: true is honest, but retire_installed_generation ORs registration into existing_install, finds no generation fence, and returns missing_generation_fence_error — the same failure by a different route.

Getting automatic recovery means not demanding a fence when the plugin tree is absent, and that is where the care is needed. The generation lock deliberately lives outside the plugin tree (see the comment on InstallGeneration::file, crates/cli/src/installation/generation.rs) precisely so fencing survives the tree being moved or deleted. So "tree is gone" does not imply "no live MCP client" — a client can still be running against the deleted tree, which is the case fencing exists to prevent. A safe version would consult the generation lock for a live holder rather than inferring liveness from the tree's absence.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

Bugissue describes bug; PR fixes bug

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions