affaan-m/ECC · error · Error

Refusing to trust install-state that changed during…

Error message

Refusing to trust install-state that changed during validation: ${plan.installStatePath}.

What it means

readOwnedDestinations fingerprints the install-state file (exists flag + sha256) before and after reading and validating it. If the two fingerprints differ, the file changed concurrently while being validated, so its contents cannot be trusted, and this error is thrown. This is a TOCTOU guard preventing a racing process or editor from swapping the state between read and verification.

Solutions

  1. Re-run the install once no other install/update process is active (ensure single-writer).
  2. Pause file-sync tools or editors watching the target directory during install.
  3. Delete the changed state file and re-run the guided install to rebuild a consistent state.

Example fix

// before: two installs racing
runInstall(planA) && runInstall(planB); // second mutates state mid-validation
// after: serialize installs
await runInstall(planA);
await runInstall(planB);
Defensive patterns

Strategy: retry

Validate before calling

const before = fingerprintFile(plan.installStatePath);
// ensure no concurrent writer before invoking
if (isInstallRunning()) throw new Error('Another install is in progress');

Type guard

function isStateStable(fp1, fp2) {
  return fp1.exists === fp2.exists && fp1.sha256 === fp2.sha256;
}

Try / catch

try {
  const owned = readOwnedDestinations(plan, deps);
} catch (err) {
  if (String(err.message).includes('changed during validation')) {
    // wait and retry once with no concurrent processes
    await waitForFileQuiet(plan.installStatePath);
    return readOwnedDestinations(plan, deps);
  }
  throw err;
}

Prevention

When it happens

Trigger: The install-state file is modified, replaced, or deleted between fingerprintFile() before readState() and the fingerprint taken after — e.g. a concurrent install/update process, an editor auto-save, or a sync tool (Dropbox/rsync) touching the file during install.

Common situations: Running two installs of ECC in parallel; a dotfile-sync service updating ~/.config while an install runs; a test or script regenerating install-state mid-run; VCS checkout/branch switch during install.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


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

Appendix: source

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

    return { destinations: new Set(), stateFingerprint: { exists: false, sha256: null } };
  }
  try {
    assertSafeInstallOperation(plan, { destinationPath: plan.installStatePath });
  } catch (error) {
    throw new Error(`Refusing to trust managed install-state path: ${error.message}`);
  }
  const initialFingerprint = fingerprintFile(plan.installStatePath);
  if (!initialFingerprint.exists) {
    return { destinations: new Set(), stateFingerprint: { exists: false, sha256: null } };
  }
  const readState = dependencies.readInstallState || require('./install-state').readInstallState;
  const state = readState(plan.installStatePath);
  const validatedFingerprint = fingerprintFile(plan.installStatePath);
  if (
    initialFingerprint.exists !== validatedFingerprint.exists
    || initialFingerprint.sha256 !== validatedFingerprint.sha256
  ) {
    throw new Error(
      `Refusing to trust install-state that changed during validation: ${plan.installStatePath}.`
    );
  }
  assertPriorInstallStateMatchesPlan(state, plan);
  const plannedByDestination = new Map(plan.operations.map(operation => [
    canonicalPath(operation.destinationPath),
    operation,
  ]));
  const destinations = new Set();
  for (const operation of state.operations || []) {
    if (operation.ownership !== 'managed') {
      throw new Error(
        `Refusing to trust non-managed ownership from install-state at ${plan.installStatePath}.`
      );
    }
    const destinationPath = operation.destinationPath;
    assertWithinTrustedRoot(destinationPath, plan.targetRoot, 'trust install-state ownership');
    const canonicalDestination = canonicalPath(destinationPath);

View on GitHub (pinned to 8321021c54)