affaan-m/ECC · error · Error
Refusing unverified ownership from install-state at
Error message
Refusing unverified ownership from install-state at ${plan.installStatePath}: operation identity does not match the current plan for ${destinationPath}. What it means
For each state operation that also appears in the current plan, operationIdentityMatches compares kind, moduleId, sourceRelativePath, strategy, and scaffoldOnly. If any field differs, the recorded ownership no longer corresponds to what the plan intends to write there, so the ownership claim is rejected with this error. This prevents stale state from authorizing a changed operation over an existing file.
Solutions
- Delete the stale install-state file and re-run the guided install so state and plan are generated together.
- Align plan and state versions: re-run preview/plan generation from the installed ECC version instead of mixing old state with a new plan.
- Verify no old state file from a previous ECC version is being read (check installStatePath); remove legacy state.
Example fix
// before: old state says copy-file, new plan says merge-json for same path // after: regenerate state fs.rmSync(plan.installStatePath); const freshPlan = buildPlan(adapter); // state recreated with matching identities
Defensive patterns
Strategy: validation
Validate before calling
for (const op of plan.operations) {
const recorded = state.operations.find(s => s.destinationPath === op.destinationPath);
if (recorded && ['kind','moduleId','sourceRelativePath','strategy','scaffoldOnly'].some(f => recorded[f] !== op[f])) {
throw new Error(`Identity mismatch at ${op.destinationPath}; regenerate install-state.`);
}
} Type guard
function identitiesMatch(stateOp, planOp) {
return ['kind','moduleId','sourceRelativePath','strategy','scaffoldOnly'].every(f => stateOp?.[f] === planOp?.[f]);
} Try / catch
try {
readOwnedDestinations(plan, deps);
} catch (err) {
if (String(err.message).includes('operation identity does not match')) {
fs.rmSync(plan.installStatePath); // stale state from another version; regenerate
} else throw err;
} Prevention
- Regenerate install-state whenever you upgrade ECC.
- Do not mix a state file from one ECC version with a plan from another.
- Run the guided preview so plan and state are produced together.
- Check ECC version recorded alongside state before reusing it.
When it happens
Trigger: A destination path exists in both state.operations and plan.operations but with a different kind/moduleId/sourceRelativePath/strategy/scaffoldOnly — e.g. the plan was regenerated after ECC updated the module's file layout, or the state was recorded by a different version of ECC.
Common situations: Upgrading ECC to a version that changed a file's kind (copy-file vs merge-json) or source path; state file left over from an older install while the plan was rebuilt; moduleId renamed in the plugin.
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
- Refusing to trust managed install-state at
- A managed install-state path is required before preflight.
- Failed to read
- Invalid install-state
- Refusing to overwrite an unowned or changed install-state at
AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16).
Data as JSON: /api/errors/f12d3720bf6e131e.
Report an issue: GitHub.
Appendix: source
Thrown at scripts/lib/multi-harness-setup.js:216
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);
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 };View on GitHub (pinned to 8321021c54)