affaan-m/ECC · error · Error
A managed install-state path is required before preflight.
Error message
A managed install-state path is required before preflight.
What it means
preflightManagedPlan requires plan.installStatePath to be a non-empty string because the preflight step must read and compare an install-state file before applying operations. An empty or missing installStatePath means the plan cannot safely checkpoint state, so it throws before touching disk.
Solutions
- Ensure the plan is built by createMultiHarnessPlan/applyMultiHarnessPlan which set installStatePath
- If building manually, set plan.installStatePath to a valid file path before preflight
- Check for empty-string paths coming from config/env interpolation
Example fix
// before
const plan = { operations: [...] };
// after
const plan = { operations: [...], installStatePath: '.ecc/install-state.json' }; Defensive patterns
Strategy: validation
Validate before calling
if (typeof plan?.installStatePath !== 'string' || plan.installStatePath.length === 0) {
throw new Error('plan.installStatePath must be a non-empty string');
} Type guard
function hasInstallStatePath(p) {
return typeof p?.installStatePath === 'string' && p.installStatePath.length > 0;
} Try / catch
try {
await preflight(plan);
} catch (e) {
if (e.message.includes('install-state path is required')) {
plan = await createMultiHarnessPlan(request); // rebuild with proper state path
} else throw e;
} Prevention
- Never strip installStatePath when serializing plans
- Interpolate config paths carefully so empty strings don't reach the plan
- Use the official plan builders instead of object literals
When it happens
Trigger: Constructing a plan manually or mutating it so installStatePath is undefined/null/empty; a plan built by an older code path that didn't set installStatePath; a serialized plan that dropped the field.
Common situations: Custom tooling around multi-harness-setup building plans by hand; tests instantiating plan fixtures without installStatePath; upgrading plans created by a previous version of the script.
Understand the failure class
Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.
Related errors
- Invalid install-state
- Refusing to trust managed install-state at
- Refusing to trust managed install-state path
- Refusing to trust non-managed ownership from install-state…
- -32602
AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16).
Data as JSON: /api/errors/17600a1260c92aef.
Report an issue: GitHub.
Appendix: source
Thrown at scripts/lib/multi-harness-setup.js:348
for (const [candidatePath, mode] of requirements) {
try {
accessSync(candidatePath, mode);
} catch (_error) {
const label = plan.target === 'kimi' ? 'Kimi' : 'Managed install';
throw new Error(
`${label} destination is not writable by the current user: ${candidatePath}. `
+ 'Fix the project ownership or permissions, then retry.'
);
}
}
}
function preflightManagedPlan(plan, dependencies = {}) {
if (!plan || !Array.isArray(plan.operations)) {
throw new Error('A managed install plan with operations is required.');
}
if (typeof plan.installStatePath !== 'string' || plan.installStatePath.length === 0) {
throw new Error('A managed install-state path is required before preflight.');
}
const ownership = readOwnedDestinations(plan, dependencies);
const operations = plan.operations.map(operation => {
assertSafeInstallOperation(plan, operation);
return {
destinationPath: operation.destinationPath,
kind: operation.kind,
classification: classifyManagedOperation(operation, ownership.destinations),
};
});
assertManagedDestinationsWritable(plan, dependencies);
return {
plan,
operations,
ownershipSnapshot: {
destinations: [...ownership.destinations],
stateFingerprint: ownership.stateFingerprint,
},View on GitHub (pinned to 8321021c54)