affaan-m/ECC · error
INVALID_SCOPE
INVALID_SCOPE
Error message
Scope migration requires --scope user, project, or local.
What it means
ClaudeSetupError with code INVALID_SCOPE thrown at the entry of migrateClaudePluginScope in scripts/lib/claude-scope-migration.js:248. The destination scope is validated against the VALID_SCOPES set ('user', 'project', 'local') before any migration work begins. Any other value — misspelled scopes, empty values, or unsupported targets like 'global' — is rejected immediately with this message so invalid input never reaches Claude CLI calls.
Solutions
- Use one of the three supported values: `--scope user`, `--scope project`, or `--scope local`.
- If the value comes from a variable, echo it first to confirm it is non-empty and correctly spelled.
- Check case — the validation is exact-match against lowercase scope names.
- If calling the JS API directly, pass `{ scope: 'project' }` (etc.) in options rather than a nested or renamed key.
Example fix
// before // ecc migrate-scope --scope global // after // ecc migrate-scope --scope user
Defensive patterns
Strategy: validation
Validate before calling
const VALID_SCOPES = new Set(['user', 'project', 'local']);
if (!VALID_SCOPES.has(scope)) {
throw new Error(`Scope migration requires --scope user, project, or local (got: ${scope})`);
} Type guard
function isValidScope(v) { return typeof v === 'string' && ['user', 'project', 'local'].includes(v); } Try / catch
try { await migrateClaudePluginScope({ scope }) }
catch (e) {
if (e.code === 'INVALID_SCOPE') { console.error(e.message); process.exitCode = 2; }
else throw e;
} Prevention
- Only use the documented scope names: user, project, local (lowercase).
- Echo shell variables used for --scope before running to catch empty values.
- Add CLI arg validation (commander/yargs choices) in wrapper scripts.
- Do not invent scope names like 'global'; check `ecc --help`.
When it happens
Trigger: Invoking the scope migration API or CLI with `options.scope` set to anything other than exactly 'user', 'project', or 'local' — e.g. `--scope global`, `--scope User` (case-sensitive), `--scope ''`, or omitting the scope entirely (undefined fails the Set check).
Common situations: Typo in a CLI flag value; assuming a 'global' or 'workspace' scope exists; shell variable expansion producing an empty --scope value; case-sensitivity mistakes ('User' vs 'user').
Understand the failure class
Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.
Related errors
- INVALID_HOOK_MODE
- all overlays must be readable local files
- all takes must be readable local files
- AMBIGUOUS_PLUGIN_SCOPES
- Arguments must not contain NUL bytes.
AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16).
Data as JSON: /api/errors/f8fa8c5b946d5978.
Report an issue: GitHub.
Appendix: source
Thrown at scripts/lib/claude-scope-migration.js:248
}
);
}
}
function verifyFinalState(run, paths, destinationScope) {
const plugins = readPluginInventory(run, paths.projectRoot, 'final-verification');
return validateExpectedScopes(plugins, [destinationScope], {
code: 'FINAL_VERIFICATION_FAILED',
destinationScope,
message: `Could not verify destination-only ${CURRENT_PLUGIN_ID} state after source cleanup.`,
phase: 'final-verification',
recovery: recoveryCommands(null, destinationScope),
});
}
function migrateClaudePluginScope(options = {}, dependencies = {}) {
if (!VALID_SCOPES.has(options.scope)) {
throw migrationError(
'INVALID_SCOPE',
'Scope migration requires --scope user, project, or local.'
);
}
if (options.hooks !== undefined && !VALID_HOOK_MODES.has(options.hooks)) {
throw migrationError('INVALID_HOOK_MODE', `Invalid hook mode: ${options.hooks}`);
}
const paths = resolveClaudePaths(options);
const settingsPath = path.join(paths.configDir, 'settings.json');
const settings = readSettings(settingsPath);
assertSafeLocalInventory(paths);
assertGitAvailable(
{ cwd: paths.projectRoot },
{ spawnSync: dependencies.spawnSync }
);
const providerRun = dependencies.runClaude || runClaude;
const run = options.dryRunView on GitHub (pinned to 8321021c54)