{"record":{"id":"6f5c616e3aaf8db4","repo":"affaan-m/ECC","slug":"canonical-session-snapshot-requires-session-source","errorCode":null,"errorMessage":"Canonical session snapshot requires session.sourceTarget to be an object","messagePattern":"Canonical session snapshot requires session\\.sourceTarget to be an object","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"scripts/lib/session-adapters/canonical-session.js","lineNumber":184,"sourceCode":"\n  ensureString(snapshot.schemaVersion, 'schemaVersion');\n  if (snapshot.schemaVersion !== SESSION_SCHEMA_VERSION) {\n    throw new Error(`Unsupported canonical session schema version: ${snapshot.schemaVersion}`);\n  }\n\n  ensureString(snapshot.adapterId, 'adapterId');\n\n  if (!isObject(snapshot.session)) {\n    throw new Error('Canonical session snapshot requires session to be an object');\n  }\n\n  ensureString(snapshot.session.id, 'session.id');\n  ensureString(snapshot.session.kind, 'session.kind');\n  ensureString(snapshot.session.state, 'session.state');\n  ensureOptionalString(snapshot.session.repoRoot, 'session.repoRoot');\n\n  if (!isObject(snapshot.session.sourceTarget)) {\n    throw new Error('Canonical session snapshot requires session.sourceTarget to be an object');\n  }\n\n  ensureString(snapshot.session.sourceTarget.type, 'session.sourceTarget.type');\n  ensureString(snapshot.session.sourceTarget.value, 'session.sourceTarget.value');\n\n  if (!Array.isArray(snapshot.workers)) {\n    throw new Error('Canonical session snapshot requires workers to be an array');\n  }\n\n  snapshot.workers.forEach((worker, index) => {\n    if (!isObject(worker)) {\n      throw new Error(`Canonical session snapshot requires workers[${index}] to be an object`);\n    }\n\n    ensureString(worker.id, `workers[${index}].id`);\n    ensureString(worker.label, `workers[${index}].label`);\n    ensureString(worker.state, `workers[${index}].state`);\n    ensureString(worker.health, `workers[${index}].health`);","sourceCodeStart":166,"sourceCodeEnd":202,"githubUrl":"https://github.com/affaan-m/ECC/blob/8321021c54d670126ce3b2969d5deb880b4b0c2a/scripts/lib/session-adapters/canonical-session.js#L166-L202","documentation":"The canonical session requires a nested session.sourceTarget object describing what the session is attached to, with string fields type and value (validated immediately after). This error throws when session.sourceTarget is null, undefined, or not an object. It keeps the origin/target metadata uniformly structured for all adapters.","triggerScenarios":"A snapshot whose session object omits sourceTarget; sourceTarget set to null or to a string like '/repo' instead of { type, value }; adapters built against an older schema where the field had a different name or flat shape.","commonSituations":"Old persisted snapshots predating the sourceTarget field; hand-crafted test fixtures; copying session data between adapters and dropping the nested object.","solutions":["Populate session.sourceTarget = { type: '<type>', value: '<string>' } (e.g. { type: 'path', value: '/repo' })","Regenerate the snapshot with the current normalize* adapter","Migrate old snapshots: wrap a legacy flat field into the { type, value } object","Check for typos like sourceTarget vs source_target"],"exampleFix":"// before\nsession.sourceTarget = '/worktrees/feature';\n// after\nsession.sourceTarget = { type: 'path', value: '/worktrees/feature' };","handlingStrategy":"type-guard","validationCode":"if (!hasSourceTarget(snap)) throw new TypeError('Missing/invalid sourceTarget');","typeGuard":"const hasSourceTarget = (v) => typeof v?.session?.sourceTarget === 'object' && v.session.sourceTarget !== null && typeof v.session.sourceTarget.type === 'string' && typeof v.session.sourceTarget.value === 'string';","tryCatchPattern":"try { persistCanonicalSnapshot(snap); } catch (e) { if (/sourceTarget to be an object/.test(e.message)) { snap.session.sourceTarget = { type: 'path', value: legacy }; } else throw e; }","preventionTips":["Model sourceTarget as {type, value}","Migrate legacy flat fields"],"tags":["validation","schema","missing-field"],"backgroundTag":"schema-validation-failed","analyzedSha":"8321021c54d670126ce3b2969d5deb880b4b0c2a","analyzedAt":"2026-09-16T10:08:13.343Z","contentChangedAt":"2026-09-16T10:08:13.343Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}