affaan-m/ECC · error
AMBIGUOUS_PLUGIN_SCOPES
AMBIGUOUS_PLUGIN_SCOPES
Error message
Cannot safely migrate ${CURRENT_PLUGIN_ID} from ambiguous scopes: ${observedScopes.join(', ')}. What it means
ClaudeSetupError with code AMBIGUOUS_PLUGIN_SCOPES thrown by assertMigrationInventory in scripts/lib/claude-scope-migration.js:83. The migrator can only proceed when the plugin inventory is unambiguous: at most 2 installations, all at distinct scopes, and if there are 2 they must include the destination scope (a resumable two-scope state). Any other combination — three or more copies, duplicate scopes, or two copies neither of which is at the destination — is unsafe to auto-repair, so the tool refuses with the observed scope list.
Solutions
- Inspect the inventory: `claude plugin list --json` and note every scope where the ECC plugin appears.
- Manually uninstall extras, keeping only the copy you want as the source: `claude plugin uninstall <plugin-id> --scope <scope> --keep-data`.
- Then re-run the migration with the single remaining source and the desired destination scope.
- If duplicates are stale registry entries rather than real installs, reinstall cleanly: uninstall everywhere, then `ecc setup --mode claude-plugin --scope <destination> --yes`.
Example fix
// before: plugin at user, project AND local scopes → ambiguous // claude plugin uninstall everything-claude-code --scope local --keep-data // claude plugin uninstall everything-claude-code --scope project --keep-data // after: single source scope remains, migration proceeds // ecc migrate-scope --scope user
Defensive patterns
Strategy: validation
Validate before calling
const plugins = parsePluginList(run(['plugin', 'list', '--json'], { cwd }).stdout)
.filter(p => p.id === CURRENT_PLUGIN_ID);
const scopes = plugins.map(p => p.scope);
const unique = new Set(scopes);
const ambiguous = plugins.length > 2 || unique.size !== plugins.length ||
(plugins.length === 2 && !unique.has(destinationScope));
if (ambiguous) throw new Error(`Resolve duplicate scopes first: ${scopes.join(', ')}`); Type guard
function hasUnambiguousInventory(plugins, dest) {
const scopes = plugins.map(p => p.scope);
const u = new Set(scopes);
return plugins.length >= 1 && plugins.length <= 2 && u.size === plugins.length &&
(plugins.length !== 2 || u.has(dest));
} Try / catch
try { await migrateScope({ scope }) }
catch (e) {
if (e.code === 'AMBIGUOUS_PLUGIN_SCOPES') {
for (const s of e.details.observedScopes) console.log('Uninstall extra copy at scope:', s);
} else throw e;
} Prevention
- Install the plugin at exactly one scope; avoid re-running setup with different --scope values without cleaning up.
- After any failed migration, run `claude plugin list --json` and remove duplicates before retrying.
- Script installs so scope changes uninstall the previous scope first.
- Audit plugin inventory periodically in CI or setup scripts.
When it happens
Trigger: Running a scope migration when `claude plugin list --json` shows the ECC plugin installed in a state like [user, project, local] (3 copies), [user, user] (duplicate scope entries), or two installations at scopes that both differ from the requested --scope destination.
Common situations: The plugin was incrementally installed at multiple scopes over time (user install then project install then local install) and now three copies exist; a partial previous migration crashed leaving duplicates; Claude's plugin registry has stale duplicate entries from a re-install that did not clean up.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- PLUGIN_NOT_INSTALLED
- SOURCE_UNINSTALL_FAILED
- DESTINATION_VERIFICATION_FAILED
- INVALID_SCOPE
- Agents directory not found
AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16).
Data as JSON: /api/errors/9617625772afb289.
Report an issue: GitHub.
Appendix: source
Thrown at scripts/lib/claude-scope-migration.js:83
'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)
)
) {
throw migrationError(
'AMBIGUOUS_PLUGIN_SCOPES',
`Cannot safely migrate ${CURRENT_PLUGIN_ID} from ambiguous scopes: ${observedScopes.join(', ')}.`,
{ observedScopes }
);
}
if (installed.length === 1 && installed[0].scope === destinationScope) {
if (installed[0].enabled !== true) {
throw migrationError(
'DESTINATION_VERIFICATION_FAILED',
`${CURRENT_PLUGIN_ID} exists at ${destinationScope} scope but is not enabled.`,
{
phase: 'destination-verification',
observedScopes,
recovery: recoveryCommands(null, destinationScope),
}
);
}View on GitHub (pinned to 8321021c54)