affaan-m/ECC · error · Error
Canonical session snapshot requires aggregates to be an…
Error message
Canonical session snapshot requires aggregates to be an object
What it means
validateCanonicalSnapshot requires snapshot.aggregates to be a plain object holding roll-up counts derived from workers. This error fires when aggregates is missing, null, or a non-object, meaning the snapshot was built without its summary section. Aggregates drive dashboards so the validator treats them as mandatory.
Solutions
- Add an aggregates object with workerCount (integer equal to workers.length), states {}, and healths {} to the snapshot.
- Compute aggregates from the workers array before persisting (counts by state and health).
- Regenerate the snapshot via the current adapters, which build aggregates automatically.
- Validate snapshots right after construction to catch missing aggregates.
Example fix
// before
const snapshot = { workers };
persistCanonicalSnapshot(snapshot);
// after
const snapshot = {
workers,
aggregates: {
workerCount: workers.length,
states: {},
healths: {}
}
};
persistCanonicalSnapshot(snapshot); Defensive patterns
Strategy: validation
Validate before calling
if (!snapshot.aggregates || typeof snapshot.aggregates !== 'object' || Array.isArray(snapshot.aggregates)) throw new Error('snapshot.aggregates must be an object'); Type guard
function hasAggregates(s) { return !!s && typeof s.aggregates === 'object' && s.aggregates !== null && !Array.isArray(s.aggregates); } Try / catch
try { persistCanonicalSnapshot(snapshot); } catch (err) { if (String(err.message).includes('aggregates to be an object')) { console.error('Snapshot missing aggregates:', err.message); /* rebuild aggregates from workers */ } else { throw err; } } Prevention
- Build snapshots through a single constructor that always emits aggregates.
- Compute aggregates from workers with a shared deriveAggregates() helper.
- Never assemble snapshots field-by-field in ad hoc scripts.
- Validate snapshots immediately after construction.
When it happens
Trigger: Passing a snapshot without the aggregates block to persistCanonicalSnapshot or a normalize* adapter; constructing a snapshot manually with only workers.
Common situations: Older snapshot format without aggregates loaded into current code; a transform that spread workers but dropped aggregates; partial JSON written by a crashed writer.
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
- Canonical session snapshot requires aggregates.healths to…
- Canonical session snapshot requires aggregates.states to be…
- Canonical session snapshot requires aggregates.workerCount…
- Canonical session snapshot requires workers
- Canonical session snapshot requires workers
AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16).
Data as JSON: /api/errors/1b4bfb1928b36ff0.
Report an issue: GitHub.
Appendix: source
Thrown at scripts/lib/session-adapters/canonical-session.js:236
ensureStringAllowEmpty(worker.intent.objective, `workers[${index}].intent.objective`);
ensureArrayOfStrings(worker.intent.seedPaths, `workers[${index}].intent.seedPaths`);
if (!isObject(worker.outputs)) {
throw new Error(`Canonical session snapshot requires workers[${index}].outputs to be an object`);
}
ensureArrayOfStrings(worker.outputs.summary, `workers[${index}].outputs.summary`);
ensureArrayOfStrings(worker.outputs.validation, `workers[${index}].outputs.validation`);
ensureArrayOfStrings(worker.outputs.remainingRisks, `workers[${index}].outputs.remainingRisks`);
if (!isObject(worker.artifacts)) {
throw new Error(`Canonical session snapshot requires workers[${index}].artifacts to be an object`);
}
});
if (!isObject(snapshot.aggregates)) {
throw new Error('Canonical session snapshot requires aggregates to be an object');
}
ensureInteger(snapshot.aggregates.workerCount, 'aggregates.workerCount');
if (snapshot.aggregates.workerCount !== snapshot.workers.length) {
throw new Error('Canonical session snapshot requires aggregates.workerCount to match workers.length');
}
if (!isObject(snapshot.aggregates.states)) {
throw new Error('Canonical session snapshot requires aggregates.states to be an object');
}
if (!isObject(snapshot.aggregates.healths)) {
throw new Error('Canonical session snapshot requires aggregates.healths to be an object');
}
for (const [state, count] of Object.entries(snapshot.aggregates.states)) {
ensureString(state, 'aggregates.states key');
ensureInteger(count, `aggregates.states.${state}`);View on GitHub (pinned to 8321021c54)