affaan-m/ECC · error · Error

Refusing unverified ownership from install-state at ${plan.i

Error message

Refusing unverified ownership from install-state at ${plan.installStatePath}: content digest does not match ${destinationPath}.

What it means

Thrown by readOwnedDestinations after the identity check passes, when the destination file's current SHA-256 does not match the operation's recorded contentSha256. This is the cryptographic proof that ECC still owns the file: even if identity matches, if the bytes on disk differ from what ECC wrote (or the file is missing, or contentSha256 is malformed), ownership is no longer verifiable and the file is treated as user-modified. The regex /^[a-f0-9]{64}$/i also rejects malformed or missing digests.

Source

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

    }
    const destinationPath = operation.destinationPath;
    assertWithinTrustedRoot(destinationPath, plan.targetRoot, 'trust install-state ownership');
    const canonicalDestination = canonicalPath(destinationPath);
    const plannedOperation = plannedByDestination.get(canonicalDestination);
    if (!plannedOperation) continue;
    if (!operationIdentityMatches(operation, plannedOperation)) {
      throw new Error(
        `Refusing unverified ownership from install-state at ${plan.installStatePath}: `
        + `operation identity does not match the current plan for ${destinationPath}.`
      );
    }
    const currentFingerprint = fingerprintFile(destinationPath);
    if (
      !currentFingerprint.exists
      || !/^[a-f0-9]{64}$/i.test(operation.contentSha256 || '')
      || currentFingerprint.sha256 !== operation.contentSha256.toLowerCase()
    ) {
      throw new Error(
        `Refusing unverified ownership from install-state at ${plan.installStatePath}: `
        + `content digest does not match ${destinationPath}.`
      );
    }
    destinations.add(canonicalDestination);
  }
  return { destinations, stateFingerprint: validatedFingerprint };
}

function assertMergeDestination(destinationPath) {
  if (!fs.existsSync(destinationPath)) return null;
  let current;
  try {
    current = JSON.parse(fs.readFileSync(destinationPath, 'utf8'));
  } catch (error) {
    throw new Error(`Cannot merge ECC configuration into invalid JSON at ${destinationPath}: ${error.message}`);
  }
  if (!current || typeof current !== 'object' || Array.isArray(current)) {

View on GitHub (pinned to 01e15490f0)

Solutions

  1. If you intentionally modified the file, remove the install-state and re-run the preview so ECC re-records ownership of the current bytes (or move your edits aside first).
  2. Restore the file to the exact bytes ECC wrote (e.g., git checkout the managed version) so the digest matches contentSha256.
  3. If contentSha256 in the state looks malformed, treat the state as corrupt: delete it and regenerate.
  4. Disable formatters/linters that rewrite ECC-managed files, or add them to the managed set explicitly.

Example fix

// before: user edited managed file, digest no longer matches state
// state op.contentSha256 = 'aa...'
// current file sha256      = 'bb...'
readOwnedDestinations(plan); // throws [288]

// after (option A): re-record ownership for the edited file
fs.rmSync(plan.installStatePath, { force: true });
const plan2 = await createMultiHarnessPlan(req);
await applyMultiHarnessPlan(plan2);

// after (option B): restore original bytes
fs.copyFileSync(originalManagedFile, destinationPath);
Defensive patterns

Strategy: validation

Validate before calling

const fs = require('fs'); const crypto = require('crypto');
function assertDestinationsMatchDigests(statePath) {
  if (!fs.existsSync(statePath)) return;
  const state = JSON.parse(fs.readFileSync(statePath, 'utf8'));
  for (const op of state.operations || []) {
    if (!fs.existsSync(op.destinationPath)) {
      throw new Error(`Managed file missing: ${op.destinationPath}`);
    }
    if (!/^[a-f0-9]{64}$/i.test(op.contentSha256 || '')) {
      throw new Error(`Malformed contentSha256 for ${op.destinationPath}`);
    }
    const cur = crypto.createHash('sha256').update(fs.readFileSync(op.destinationPath)).digest('hex');
    if (cur !== op.contentSha256.toLowerCase()) {
      throw new Error(`Managed file modified externally: ${op.destinationPath}`);
    }
  }
}
assertDestinationsMatchDigests(plan.installStatePath);

Type guard

null

Try / catch

try {
  await applyMultiHarnessPlan(plan);
} catch (err) {
  if (/content digest does not match/.test(err.message)) {
    // decide: re-record ownership (delete state + re-preview) or restore the original bytes
    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 fingerprintFile(destinationPath).exists is false, when operation.contentSha256 is not a valid 64-char hex digest, or when the current sha256 differs from contentSha256.toLowerCase(). Occurs when the user edited an ECC-managed file, another tool rewrote it (formatter, postinstall), the file was deleted, or the state's contentSha256 field was corrupted/uppercased/truncated.

Common situations: User hand-editing an ECC-managed config file; a linter/formatter rewriting a managed file on save; partial checkout where the file is missing; git line-ending normalization changing the digest; state corruption altering contentSha256; cross-platform EOL differences changing the hash.

Related errors


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