affaan-m/ECC · error · Error

Refusing to trust managed install-state at ${plan.installSta

Error message

Refusing to trust managed install-state at ${plan.installStatePath}: recorded root does not match the current install root.

What it means

Thrown by assertPriorInstallStateMatchesPlan when the install-state's recorded target.root (canonicalized via realpathNearestExisting) does not equal plan.targetRoot. ECC scopes ownership to a concrete project root; a state recorded under a different root cannot vouch for files in the current project. This blocks attacks/mistakes where a state file is copied or symlinked from elsewhere to claim ownership it does not have.

Source

Thrown at scripts/lib/multi-harness-setup.js:112

    );
  }
}

function assertPriorInstallStateMatchesPlan(state, plan) {
  const target = state.target || {};
  const adapter = plan.adapter || {};
  if (
    target.id !== adapter.id
    || target.target !== adapter.target
    || target.kind !== adapter.kind
  ) {
    throw new Error(
      `Refusing to trust managed install-state at ${plan.installStatePath}: `
      + 'target identity does not match the current Kimi install plan.'
    );
  }
  if (!pathsMatch(target.root, plan.targetRoot)) {
    throw new Error(
      `Refusing to trust managed install-state at ${plan.installStatePath}: `
      + 'recorded root does not match the current install root.'
    );
  }
  if (!pathsMatch(target.installStatePath, plan.installStatePath)) {
    throw new Error(
      `Refusing to trust managed install-state at ${plan.installStatePath}: `
      + 'recorded install-state path does not match the current install-state path.'
    );
  }
}

function readOwnedDestinations(plan, dependencies) {
  if (!plan.installStatePath) {
    return { destinations: new Set(), stateFingerprint: { exists: false, sha256: null } };
  }
  try {
    assertSafeInstallOperation(plan, { destinationPath: plan.installStatePath });

View on GitHub (pinned to 01e15490f0)

Solutions

  1. Delete plan.installStatePath and re-run createMultiHarnessPlan so target.root is recorded for the current plan.targetRoot.
  2. Run preview and apply from the same working directory with the same HOME so plan.targetRoot resolves identically.
  3. If the project was moved intentionally, treat it as a fresh install (discard old state).
  4. Inspect target.root vs plan.targetRoot in the JSON to confirm the path mismatch is the cause and not a realpath/symlink artifact.

Example fix

// before: project moved from ~/dev/app to ~/code/app, old state retained
// state.target.root = '/home/me/dev/app'
// plan.targetRoot      = '/home/me/code/app'
await applyMultiHarnessPlan(plan); // throws [282]

// after: re-record state for the new root
fs.rmSync(plan.installStatePath, { force: true });
const plan2 = await createMultiHarnessPlan(req);
await applyMultiHarnessPlan(plan2);
Defensive patterns

Strategy: validation

Validate before calling

const fs = require('fs'); const path = require('path');
function assertStateRootMatches(statePath, targetRoot) {
  if (!fs.existsSync(statePath)) return;
  const state = JSON.parse(fs.readFileSync(statePath, 'utf8'));
  const recorded = path.resolve(state.target && state.target.root || '');
  const current = path.resolve(targetRoot);
  if (recorded !== current) {
    throw new Error(`Install-state recorded root ${recorded} != current ${current}; remove the state or move the project back.`);
  }
}
assertStateRootMatches(plan.installStatePath, plan.targetRoot);

Type guard

null

Try / catch

try {
  await applyMultiHarnessPlan(plan);
} catch (err) {
  if (/recorded root does not match the current install root/.test(err.message)) {
    fs.rmSync(plan.installStatePath, { force: true });
    const fresh = await createMultiHarnessPlan(plan.request);
    await applyMultiHarnessPlan(fresh);
  } else throw err;
}

Prevention

When it happens

Trigger: Fires when pathsMatch(target.root, plan.targetRoot) is false inside readOwnedDestinations. Happens if the project was moved/cloned to a new path but the old install-state was kept, if plan.targetRoot was computed from a different cwd/HOME than when the state was written, or if symlinks cause realpath to resolve the same logical path to different canonical strings.

Common situations: Copying a project folder that includes .claude/ and continuing the install from the new location; running ECC from a container with a different mount path than the host; HOME or cwd resolving differently between the preview run and the apply run; symlinked project roots where one side resolved and the other did not.

Related errors


AI-assisted analysis of affaan-m/ECC@01e15490f0 (2026-08-13). Data as JSON: /api/errors/cdae627986f8d40b. Report an issue: GitHub.