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.
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
--forcerecovery path the error messages point users toward.codex plugin listrefuses to run while any configured marketplace snapshot fails to load:Relay surfaces the host CLI's failure verbatim. The probe is
codex_plugin_registered/codex_marketplace_registeredincrates/cli/src/installation/marketplace/host.rs, both of which callrun_capture_command, which converts any non-zero exit into an error (host.rs:395). Becausehost_registration_reportruns 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 --forceshould recover on its own, since it is what every error message recommends.Steps to reproduce
Current workaround — unregister by hand, after which #965's fix takes over and everything recovers:
Environment
release/0.8@bca07ecd(also reproduces with fix(install): recover from orphaned plugin state in install, uninstall, and refresh #965 merged)cargo build -p nemo-relay-cli --bin nemo-relayImpact
Affects any Codex user who removes the marketplace directory without unregistering first. There is a workaround (the manual
codex plugin removesequence above), but it is not discoverable from the error, which points atcodex plugin listrather 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 listfails and stderr namesnemo-relay-localas 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
--forceactually recover (needs a decision). The tolerant probe alone is likely not sufficient. Reportinghost_marketplace_registered: trueis honest, butretire_installed_generationORs registration intoexisting_install, finds no generation fence, and returnsmissing_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.