{"record":{"id":"66cb2af93a9fbb5f","repo":"thedotmack/claude-mem","slug":"agent-event-id-must-belong-to-project-id-and-team","errorCode":null,"errorMessage":"agent_event_id must belong to project_id and team_id","messagePattern":"agent_event_id must belong to project_id and team_id","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/storage/postgres/observations.ts","lineNumber":372,"sourceCode":"  }\n  if (input.sourceType === 'agent_event' && row.agent_event_id !== input.agentEventId) {\n    throw new Error('generation_job_id agent_event_id must match observation source');\n  }\n}\n\nasync function assertAgentEventOwnership(\n  client: PostgresQueryable,\n  agentEventId: string,\n  projectId: string,\n  teamId: string\n): Promise<void> {\n  const row = await queryOne<{ id: string }>(\n    client,\n    'SELECT id FROM agent_events WHERE id = $1 AND project_id = $2 AND team_id = $3',\n    [agentEventId, projectId, teamId]\n  );\n  if (!row) {\n    throw new Error('agent_event_id must belong to project_id and team_id');\n  }\n}\n\nasync function assertObservationOwnership(\n  client: PostgresQueryable,\n  observationId: string,\n  projectId: string,\n  teamId: string\n): Promise<void> {\n  const row = await queryOne<{ id: string }>(\n    client,\n    'SELECT id FROM observations WHERE id = $1 AND project_id = $2 AND team_id = $3',\n    [observationId, projectId, teamId]\n  );\n  if (!row) {\n    throw new Error('observation_reindex source_id must belong to project_id and team_id');\n  }\n}","sourceCodeStart":354,"sourceCodeEnd":390,"githubUrl":"https://github.com/thedotmack/claude-mem/blob/d768ba364302d12b76e69e4f021f0bb1d2d50ed6/src/storage/postgres/observations.ts#L354-L390","documentation":"Thrown by assertAgentEventOwnership (private helper) when addSource is called with sourceType 'agent_event'. It looks up agent_events by (id=sourceId, project_id, team_id); a missing row means the referenced event is not in scope for that tenant.","triggerScenarios":"Calling addSource({sourceType:'agent_event', sourceId}) where the agent_event does not exist for the supplied project/team. Fires after the sourceId==agentEventId invariant check passes.","commonSituations":"Referencing an event from another tenant; event expired/deleted; wrong project/team id threaded through; using an external id instead of the stored agent_event id.","solutions":["Verify the agent_event exists in scope before adding it as a source.","Confirm the event was ingested under the same project/team.","Use the agent_event id exactly as stored in agent_events."],"exampleFix":"// before\nawait sources.addSource({ observationId, projectId, teamId, sourceType:'agent_event', sourceId: maybeWrongId });\n// after\nconst evt = await agentEvents.getByIdForScope({ id: sourceId, projectId, teamId });\nif (!evt) throw new Error('agent_event not in scope');\nawait sources.addSource({ observationId, projectId, teamId, sourceType:'agent_event', sourceId });","handlingStrategy":"validation","validationCode":"const evt = await agentEvents.getByIdForScope({ id: sourceId, projectId, teamId });\nif (!evt) throw new Error('agent_event not in scope');","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Ingest agent_events into the right tenant before referencing them as observation sources."],"tags":["postgres","validation","multi-tenant","ownership","observations"],"backgroundTag":null,"analyzedSha":"d768ba364302d12b76e69e4f021f0bb1d2d50ed6","analyzedAt":"2026-08-12T23:52:55.241Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}