affaan-m/ECC · error

PLUGIN_NOT_INSTALLED

PLUGIN_NOT_INSTALLED

Error message

${CURRENT_PLUGIN_ID} is not installed, so there is no source scope to migrate.

What it means

ClaudeSetupError with code PLUGIN_NOT_INSTALLED thrown by assertMigrationInventory in scripts/lib/claude-scope-migration.js:64. Scope migration moves an installed ECC Claude plugin between scopes (user/project/local), so it requires at least one installed instance of the current plugin ID. When `claude plugin list --json` shows zero ECC plugin installations, there is no source scope to migrate from, so the command aborts and suggests running `ecc setup` to install at the destination scope instead.

Solutions

  1. Install the plugin at the desired destination scope: `ecc setup --mode claude-plugin --scope <user|project|local> --yes` (the recovery command included in the error details).
  2. Verify the plugin is actually visible to Claude: `claude plugin list --json` — confirm an entry matching the ECC plugin ID appears.
  3. If you believe it is installed, check that you are running the command from the same project root / user config Claude reads; a different configDir hides the install.
  4. If the plugin ID changed across versions, update ECC (`npm update` / git pull) so CURRENT_PLUGIN_ID matches what Claude reports.

Example fix

// before: migrate with nothing installed
// ecc migrate-scope --scope project

// after: install first, then migrate if needed
// ecc setup --mode claude-plugin --scope project --yes
Defensive patterns

Strategy: validation

Validate before calling

const list = JSON.parse(run(['plugin', 'list', '--json'], { cwd }).stdout);
const installed = list.filter(p => p.id === CURRENT_PLUGIN_ID);
if (installed.length === 0) {
  console.error('ECC plugin not installed; run: ecc setup --mode claude-plugin --scope <scope> --yes');
  process.exit(1);
}

Type guard

function isInstalled(plugins, pluginId) { return Array.isArray(plugins) && plugins.some(p => p && p.id === pluginId); }

Try / catch

try { await migrateScope({ scope }) }
catch (e) {
  if (e.code === 'PLUGIN_NOT_INSTALLED') {
    console.log('Run the recovery command:', e.details.recovery[0]);
  } else throw e;
}

Prevention

When it happens

Trigger: Calling migrateClaudePluginScope (via `ecc` scope-migration commands) with a --scope destination when the plugin inventory from `claude plugin list --json` contains no entries whose plugin ID matches CURRENT_PLUGIN_ID — i.e., ECC was never installed, or was fully uninstalled before the migration attempt.

Common situations: Running the migration on a fresh machine before ever running `ecc setup`; uninstalling the plugin manually with `claude plugin uninstall` and then trying to 'migrate' the leftover config; a typo'd or changed plugin ID in a newer ECC version making the inventory lookup miss an existing install.

Understand the failure class

Background: "Not found" and "does not exist" errors: why "Task not found", "No such folder", and "Can't find" fire when a lookup comes back empty — this error's family across 14 libraries.

Related errors


AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16). Data as JSON: /api/errors/b6dc156f0936063d. Report an issue: GitHub.

Appendix: source

Thrown at scripts/lib/claude-scope-migration.js:64

}

function readPluginInventory(run, projectRoot, phase) {
  return parsePluginList(
    run(
      ['plugin', 'list', '--json'],
      { cwd: projectRoot, phase }
    ).stdout
  );
}

function assertMigrationInventory(plugins, destinationScope) {
  assertNoConflictingEccPlugins(plugins);
  const installed = currentEccPlugins(plugins);
  const observedScopes = installed.map(plugin => plugin.scope);
  const uniqueScopes = new Set(observedScopes);

  if (installed.length === 0) {
    throw migrationError(
      'PLUGIN_NOT_INSTALLED',
      `${CURRENT_PLUGIN_ID} is not installed, so there is no source scope to migrate.`,
      {
        observedScopes,
        recovery: [
          `ecc setup --mode claude-plugin --scope ${destinationScope} --yes`,
        ],
      }
    );
  }
  if (
    installed.length > 2
    || uniqueScopes.size !== installed.length
    || (
      installed.length === 2
      && !uniqueScopes.has(destinationScope)
    )
  ) {

View on GitHub (pinned to 8321021c54)