Synced plugins: startup race with generation rename (~g2) yields spurious 'commands path not found'

Status Fixed / completed
Maintainer reply None cached
Activity 0 comments · opened Sep 25, 2026 · closed Oct 10, 2026

Summary

At startup, org-synced plugins (plugins/synced/<org>_<user>/) can report commands path not found. This happens when a sync round renames a plugin's directory to a generation suffix (<name>~g2) while the loader is still resolving the old, unsuffixed path. A fresh load resolves correctly, so the error is transient but alarming (it shows as ✘).

Observed (v2.1.282, Windows 11)

Startup plugin report:

✘ synced[0]
   commands path not found: C:\Users\<u>\.claude\plugins\synced\<org>_<user>\due-diligence
   Check that the path in your manifest or marketplace config is correct

✘ synced[9]
   commands path not found: C:\Users\<u>\.claude\plugins\synced\<org>_<user>\gsuite-skills

On disk at that moment:

  • due-diligence~g2/ and gsuite-skills~g2/ exist (plus *.meta.json); no unsuffixed dirs remain
  • manifest.json entries for both carry "generation": 2
  • .last-complete-round mtime equals the session start time (02:31), i.e. a sync round completed during startup
  • neither plugin declares commands in plugin.json; the loader is checking the default commands/ under the stale dir

Running claude plugin list a few minutes later shows both as ✔ loaded from the ~g2 paths, and the error is gone.

Repro (likely)

  1. Be a member of an org with synced plugins.
  2. Republish a plugin so its generation bumps (dir renamed <name> → <name>~g2).
  3. Start Claude Code while that sync round is in flight.
  4. The startup report shows commands path not found for the old unsuffixed path.

Why it matters

The message says to "check the path in your manifest or marketplace config", which sends users off debugging a config that's fine. Synced dirs aren't user-editable anyway.

Proposed fix

  • Cheap: when the commands/skills path is a default (not declared in plugin.json) and missing, skip silently instead of erroring. Or re-resolve the synced plugin dir from manifest.json + generation before reporting.
  • Proper: have the loader resolve synced plugins from one consistent snapshot. Either wait for the in-flight sync round to finish (or take a lock) before enumerating, or have the sync swap directories atomically (stage, then rename) so a loader never sees a half-renamed set.

View original on GitHub ↗