affaan-m/ECC · error · Error
Managed Claude install-state is invalid at ${statePath}
Error message
Managed Claude install-state is invalid at ${statePath} What it means
Thrown by validateManagedState in scripts/lib/install/inventory.js (two throw sites: structural check at line 80, per-operation check at line 91). The structural check requires state.schemaVersion === 'ecc.install.v1', state.target to be a non-array object, state.resolution.selectedModules to be an array of non-empty strings, and state.operations to be an array. The per-operation check requires each operation to be an object with an absolute destinationPath that isWithinRoot(expectedRoot). The expectedRoot confinement is security-critical: install-state is project-local and therefore attacker-controllable, so a state file that records a write outside the trusted root is treated as invalid rather than honored (see the GHSA note in path-safety.js).
Source
Thrown at scripts/lib/install/inventory.js:80
};
}
}
return null;
}
function validateManagedState(state, statePath, expectedRoot) {
const selectedModules = state?.resolution?.selectedModules;
const operations = state?.operations;
if (
state?.schemaVersion !== 'ecc.install.v1'
|| !state.target
|| typeof state.target !== 'object'
|| Array.isArray(state.target)
|| !Array.isArray(selectedModules)
|| !selectedModules.every(moduleId => typeof moduleId === 'string' && moduleId.length > 0)
|| !Array.isArray(operations)
) {
throw new Error(`Managed Claude install-state is invalid at ${statePath}`);
}
for (const operation of operations) {
if (
!operation
|| typeof operation !== 'object'
|| typeof operation.destinationPath !== 'string'
|| !path.isAbsolute(operation.destinationPath)
|| !isWithinRoot(operation.destinationPath, expectedRoot)
) {
throw new Error(`Managed Claude install-state is invalid at ${statePath}`);
}
}
return { selectedModules, operations };
}
function operationOverlapsPlugin(operation, expectedRoot) {View on GitHub (pinned to 01e15490f0)
Solutions
- Read the file at statePath and check schemaVersion first — it must be exactly 'ecc.install.v1'.
- Verify state.target is an object, state.resolution.selectedModules is an array of non-empty strings, and state.operations is an array.
- Verify every operations[].destinationPath is absolute and resolves within expectedRoot (the .claude dir or project .claude dir).
- If the file is from an older ECC version, back it up and remove it, then reinstall.
- If any destinationPath is outside the root, treat it as a potential tampering signal and audit the source of the state file before deleting.
Example fix
// before (install-state.json)
{ "schemaVersion": "ecc.install.v0", "target": {}, "operations": [] }
// after
{
"schemaVersion": "ecc.install.v1",
"target": { "id": "claude" },
"resolution": { "selectedModules": ["core"] },
"operations": []
} Defensive patterns
Strategy: validation
Validate before calling
function looksLikeValidState(s, expectedRoot) {
if (!s || s.schemaVersion !== 'ecc.install.v1') return false;
if (!s.target || typeof s.target !== 'object' || Array.isArray(s.target)) return false;
if (!Array.isArray(s.resolution?.selectedModules)) return false;
if (!s.resolution.selectedModules.every(m => typeof m === 'string' && m.length > 0)) return false;
if (!Array.isArray(s.operations)) return false;
const { isWithinRoot } = require('../path-safety');
return s.operations.every(o =>
o && typeof o === 'object'
&& typeof o.destinationPath === 'string'
&& path.isAbsolute(o.destinationPath)
&& isWithinRoot(o.destinationPath, expectedRoot)
);
}
if (!looksLikeValidState(state, expectedRoot)) {
throw new Error(`State at ${statePath} is structurally invalid or contains out-of-root operations`);
} Type guard
function isManagedState(v, expectedRoot) {
const { isWithinRoot } = require('../path-safety');
return Boolean(
v && v.schemaVersion === 'ecc.install.v1'
&& v.target && typeof v.target === 'object' && !Array.isArray(v.target)
&& Array.isArray(v.resolution?.selectedModules)
&& v.resolution.selectedModules.every(m => typeof m === 'string' && m.length > 0)
&& Array.isArray(v.operations)
&& v.operations.every(o => o && typeof o === 'object'
&& typeof o.destinationPath === 'string'
&& path.isAbsolute(o.destinationPath)
&& isWithinRoot(o.destinationPath, expectedRoot))
);
} Try / catch
try {
findManagedClaudeInstalls();
} catch (err) {
if (/Managed Claude install-state is invalid/.test(err.message)) {
console.error('State file is structurally invalid or tampered — audit and reinstall.');
}
throw err;
} Prevention
- Never manually edit install-state.json.
- Upgrade ECC in lockstep with reinstalling so the state schema matches.
- Treat any operation whose destinationPath resolves outside the adapter root as a security incident — audit the source of the state file.
- Remove partial state files after a crashed install before retrying.
When it happens
Trigger: An install-state.json with a wrong/missing schemaVersion, missing or non-object target, malformed selectedModules (non-strings, empties, or not an array), or any operation whose destinationPath is relative or resolves outside the adapter-derived expectedRoot.
Common situations: An old install-state from a previous ECC schema version; a tampered state file (security-relevant — the containment check blocks malicious state from triggering writes outside the root); a hand-edited file; cross-platform path differences (relative vs absolute).
Related errors
- Invalid install-state${label ? ` (${label})` : ''}: ${format
- Invalid ECC repo root: missing install script at ${installAp
- TypeScript compiler not found. Install root dev dependencies
- Missing value for --target
- Unknown catalog command: ${options.command}
AI-assisted analysis of affaan-m/ECC@01e15490f0 (2026-08-13).
Data as JSON: /api/errors/a83a8b2f86328adf.
Report an issue: GitHub.