{"record":{"id":"e0667ac2e071c39e","repo":"affaan-m/ECC","slug":"invalid-installstate-identity-targetid-must-be-a","errorCode":null,"errorMessage":"Invalid installState identity: targetId must be a non-empty string","messagePattern":"Invalid installState identity: targetId must be a non-empty string","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"scripts/lib/state-store/queries.js","lineNumber":359,"sourceCode":"      ? []\n      : installState.modules,\n    operations: installState.operations === undefined || installState.operations === null\n      ? []\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  };","sourceCodeStart":341,"sourceCodeEnd":377,"githubUrl":"https://github.com/affaan-m/ECC/blob/8321021c54d670126ce3b2969d5deb880b4b0c2a/scripts/lib/state-store/queries.js#L341-L377","documentation":"normalizeInstallStateIdentity validates targetId after confirming the identity object exists. If targetId is absent or not a non-empty string — undefined, null, number, or '' — this field-specific error is thrown. It narrows error 558: the identity object was passed, but its targetId field is invalid.","triggerScenarios":"Calling installState APIs with { targetRoot } but no targetId; targetId set to a numeric id from a database row; targetId coming from an empty form field or empty env/config value; property-name typo like targetID or target_id so identity.targetId is undefined.","commonSituations":"Schema drift where the id field was renamed upstream; serialization that dropped the field; constructing the identity manually from a partial record; casing mismatches between snake_case data and camelCase API.","solutions":["Ensure targetId is a non-empty string, e.g. { targetId: 'my-target', targetRoot: '/path/to/root' }","Convert numeric ids with String(id) before calling","Check for property-name/casing mismatches (target_id vs targetId) and map fields explicitly","Validate at the boundary: if (typeof id !== 'string' || !id.length) fail early with a clearer message"],"exampleFix":"// before\nnormalizeInstallStateIdentity({ targetRoot: root, targetID: 42 }); // wrong key/type\n// after\nnormalizeInstallStateIdentity({ targetId: String(id), targetRoot: root });","handlingStrategy":"type-guard","validationCode":"const { targetId, targetRoot } = identity ?? {};\nif (typeof targetId !== 'string' || targetId.length === 0) {\n  throw new Error(`targetId must be a non-empty string, got ${JSON.stringify(targetId)}`);\n}\nif (typeof targetRoot !== 'string' || targetRoot.length === 0) {\n  throw new Error('targetRoot must be a non-empty string');\n}","typeGuard":"function hasValidIdentityFields(x) {\n  return typeof x?.targetId === 'string' && x.targetId.length > 0 &&\n         typeof x?.targetRoot === 'string' && x.targetRoot.length > 0;\n}","tryCatchPattern":"try {\n  return installStateQuery(identity);\n} catch (err) {\n  if (err.message.includes('targetId must be a non-empty string')) {\n    console.error('targetId missing/empty — check upstream record mapping');\n    return null;\n  } throw err;\n}","preventionTips":["Map snake_case data fields (target_id) to camelCase explicitly before building identity","Convert numeric ids with String() before constructing the identity object","Validate identity objects once at ingestion, not at each query site","Watch for property-name typos (targetID vs targetId) with a shared constructor helper"],"tags":["validation","identity"],"backgroundTag":"invalid-identifier-format","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"}