affaan-m/ECC · error

FINAL_VERIFICATION_FAILED

FINAL_VERIFICATION_FAILED

Error message

Could not verify destination-only ${CURRENT_PLUGIN_ID} state after source cleanup.

What it means

After a plugin scope migration removes the plugin from the source scope, verifyFinalState re-reads the plugin inventory and asserts the plugin now exists in the destination scope ONLY. If the final inventory does not match that expectation, it throws FINAL_VERIFICATION_FAILED with a message stating the destination-only state could not be verified, plus recovery commands. This prevents declaring success on a migration that left the system inconsistent.

Solutions

  1. Run the recoveryCommands included in the error to re-register the plugin in the destination scope
  2. Re-run migrateClaudePluginScope after closing other Claude Code sessions that may hold plugin state
  3. Manually inspect the destination scope's plugin config and the source scope's remnants, then remove duplicates
  4. Retry after any file-sync/lock settles, then confirm only the destination scope lists the plugin

Example fix

// before: destination config missing the plugin
{ "plugins": [] }

// after (or run the suggested recovery command)
{ "plugins": [{ "id": "everything-claude-code", "scope": "user" }] }
Defensive patterns

Strategy: retry

Validate before calling

// before migrating, confirm no other session holds plugin state:
// lsof <projectRoot>/.claude/plugins* and ensure destination config lists no conflicting entries

Try / catch

try { await migrateClaudePluginScope(); } catch (e) { if (e.code === 'FINAL_VERIFICATION_FAILED') { /* run e.recovery commands, then re-run migration */ } else throw e; }

Prevention

When it happens

Trigger: migrateClaudePluginScope completes source cleanup but the final plugin inventory read shows the plugin missing from the destination scope, still present in the source scope, or the inventory file is unreadable/stale at the final-verification phase.

Common situations: Another process (Claude Code itself) rewrote plugin state between cleanup and verification; file locks or sync delays making the freshly written destination config not yet visible to the inventory reader; concurrent migrations racing on the same project root; a partially failed cleanup step earlier in the migration.

Related errors


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

Appendix: source

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

    } catch {
      // Preserve the safest known two-scope state in the structured recovery.
    }
    throw migrationError(
      'SOURCE_UNINSTALL_FAILED',
      `The destination is installed, but Claude could not remove the ${migration.sourceScope} source scope.`,
      {
        phase: 'source-uninstall',
        observedScopes,
        recovery: recoveryCommands(migration.sourceScope, destinationScope),
      }
    );
  }
}

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}`);
  }

View on GitHub (pinned to 8321021c54)