{"record":{"id":"01ee6618ed9f4b1c","repo":"affaan-m/ECC","slug":"invalid-installstate-identity-targetroot-must-be","errorCode":null,"errorMessage":"Invalid installState identity: targetRoot must be a non-empty string","messagePattern":"Invalid installState identity: targetRoot must be a non-empty string","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"scripts/lib/state-store/queries.js","lineNumber":362,"sourceCode":"      ? []\n      : installState.operations,\n    installedAt: installState.installedAt || new Date().toISOString(),\n    sourceVersion: installState.sourceVersion ?? null,\n  };\n}\n\nfunction normalizeInstallStateIdentity(identity) {\n  if (!identity || typeof identity !== 'object') {\n    throw new Error('Invalid installState identity: expected targetId and targetRoot');\n  }\n\n  const targetId = identity.targetId;\n  const targetRoot = identity.targetRoot;\n  if (typeof targetId !== 'string' || targetId.length === 0) {\n    throw new Error('Invalid installState identity: targetId must be a non-empty string');\n  }\n  if (typeof targetRoot !== 'string' || targetRoot.length === 0) {\n    throw new Error('Invalid installState identity: targetRoot must be a non-empty string');\n  }\n\n  return { targetId, targetRoot };\n}\n\nfunction normalizeGovernanceEventInput(governanceEvent) {\n  return {\n    id: governanceEvent.id,\n    sessionId: governanceEvent.sessionId ?? null,\n    eventType: governanceEvent.eventType,\n    payload: governanceEvent.payload ?? null,\n    resolvedAt: governanceEvent.resolvedAt ?? null,\n    resolution: governanceEvent.resolution ?? null,\n    createdAt: governanceEvent.createdAt || new Date().toISOString(),\n  };\n}\n\nfunction normalizeWorkItemInput(workItem) {","sourceCodeStart":344,"sourceCodeEnd":380,"githubUrl":"https://github.com/affaan-m/ECC/blob/8321021c54d670126ce3b2969d5deb880b4b0c2a/scripts/lib/state-store/queries.js#L344-L380","documentation":"normalizeInstallStateIdentity validates the install-state identity object before it is stored or queried. It requires both targetId and targetRoot to be non-empty strings and throws as soon as targetRoot fails that check. This guards the state store against records keyed by malformed identities.","triggerScenarios":"Calling normalized() (or any query passing through it) with identity.targetRoot set to undefined, null, an empty string, a number, or a non-string value while targetId happens to be valid.","commonSituations":"Constructing an identity object by hand and forgetting targetRoot; reading a partially-populated config file where the root key is missing; deserializing JSON records from an older schema that lacks the field.","solutions":["Set identity.targetRoot to a non-empty string (e.g. the absolute path of the installation root) before calling normalized().","Log or inspect the identity object at the call site to confirm which field is missing or wrongly typed.","If targetRoot comes from user input or config, validate/coerce it at load time with typeof checks.","Upgrade any producer of these records that predates the targetRoot field so it always emits it."],"exampleFix":"// before\nstore.normalized({ targetId: 'ecc' });\n// after\nstore.normalized({ targetId: 'ecc', targetRoot: '/home/user/.claude' });","handlingStrategy":"validation","validationCode":"function assertIdentity(identity) {\n  if (!identity || typeof identity.targetId !== 'string' || identity.targetId.length === 0) throw new TypeError('targetId must be a non-empty string');\n  if (typeof identity.targetRoot !== 'string' || identity.targetRoot.length === 0) throw new TypeError('targetRoot must be a non-empty string');\n}","typeGuard":"const hasTargetRoot = (i) => typeof i?.targetRoot === 'string' && i.targetRoot.length > 0;","tryCatchPattern":"try {\n  const normalized = store.normalized(identity);\n} catch (e) {\n  if (String(e.message).includes('targetRoot must be a non-empty string')) {\n    console.error('installState identity missing targetRoot:', identity);\n  }\n  throw e;\n}","preventionTips":["Always build identities through a factory function that requires both fields.","Validate config objects at load time, not at query time.","Type the identity shape in TypeScript with non-optional fields.","Add a unit test asserting the identity shape before persistence."],"tags":["validation","state-store","argument-error"],"backgroundTag":"empty-required-field","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"}