affaan-m/ECC · error · Error
Invalid canonical install-state: required projection fields…
Error message
Invalid canonical install-state: required projection fields are missing
What it means
buildInstallStateStoreRecord projects a canonical install-state into a storage record, but first requires the state object to carry all four mandatory sections: target, request, resolution, and source. If any of them is missing (or state itself is null/undefined), the projection is considered invalid and this error is thrown. It signals a corrupt or truncated install-state rather than a bad individual field value.
Solutions
- Log/inspect the state object and ensure target, request, resolution, and source are all present before calling
- Rebuild the install-state through the library's canonical creation path instead of hand-assembling it
- If data came from disk, validate it against the expected schema and re-run the install to regenerate the state
- After an upgrade, migrate old states to the new shape before projecting
Example fix
// before
buildInstallStateStoreRecord({ target, request }); // missing resolution & source
// after
buildInstallStateStoreRecord({ target, request, resolution, source }); Defensive patterns
Strategy: validation
Validate before calling
const REQUIRED = ['target', 'request', 'resolution', 'source'];
const missing = REQUIRED.filter(k => !state?.[k]);
if (missing.length) {
throw new Error(`install-state missing sections: ${missing.join(', ')}`);
} Type guard
function isCompleteInstallState(s) {
return Boolean(s && s.target && s.request && s.resolution && s.source);
} Try / catch
try {
const record = buildInstallStateStoreRecord(state);
} catch (err) {
if (err.message.startsWith('Invalid canonical install-state')) {
console.error('State object incomplete — regenerate via canonical install flow');
state = regenerateInstallState();
return buildInstallStateStoreRecord(state);
} throw err;
} Prevention
- Build install-states only through the library's canonical creation path
- Validate JSON loaded from disk against the state schema before projecting
- After upgrades, run state migrations before touching stored records
- Never hand-write partial fixture objects for required sections
When it happens
Trigger: Calling buildInstallStateStoreRecord with null/undefined, or with a state object built by an older/different version missing e.g. resolution or source; destructuring an incomplete record loaded from disk and passing the fragment in; a partial object literal in tests.
Common situations: Schema drift after a library upgrade renamed or removed one of the sections; a migration that copied only part of the state; hand-constructed fixtures missing optional-looking sections that are actually required; loading a JSON file that was truncated by a crashed write.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- -32602
- artifact path must be a non-empty relative path
- assets must be a nonempty list
- built an invalid spec
- Canonical session snapshot must be an object
AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16).
Data as JSON: /api/errors/0cf45429aab0002d.
Report an issue: GitHub.
Appendix: source
Thrown at scripts/lib/state-store/install-state-projection.js:21
const path = require('path');
const MANAGED_FILE_HEALTH_CODES = new Set([
'missing-target-root',
'unsafe-managed-destination',
'unsafe-repair-source',
'missing-managed-files',
'drifted-managed-files',
'missing-source-files',
'unverified-managed-operations',
]);
function cloneJsonValue(value) {
return value === undefined ? undefined : JSON.parse(JSON.stringify(value));
}
function buildInstallStateStoreRecord(state) {
if (!state || !state.target || !state.request || !state.resolution || !state.source) {
throw new Error('Invalid canonical install-state: required projection fields are missing');
}
return {
targetId: state.target.id,
targetRoot: state.target.root,
profile: state.request.profile ?? null,
modules: Array.isArray(state.resolution.selectedModules)
? [...state.resolution.selectedModules]
: [],
operations: Array.isArray(state.operations)
? state.operations.map(operation => cloneJsonValue(operation))
: [],
installedAt: state.installedAt,
sourceVersion: state.source.repoVersion ?? null,
};
}
function warningFor(record, code, message) {View on GitHub (pinned to 8321021c54)