{"record":{"id":"4da2853bafb5ad54","repo":"thedotmack/claude-mem","slug":"observation-id-does-not-exist","errorCode":null,"errorMessage":"observation_id does not exist","messagePattern":"observation_id does not exist","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/storage/postgres/observations.ts","lineNumber":219,"sourceCode":"\n  async addSource(input: {\n    id?: string;\n    observationId: string;\n    projectId: string;\n    teamId: string;\n    sourceType: ObservationSourceType;\n    sourceId: string;\n    agentEventId?: string | null;\n    generationJobId?: string | null;\n    metadata?: JsonObject;\n  }): Promise<PostgresObservationSource> {\n    const observation = await queryOne<{ id: string }>(\n      this.client,\n      'SELECT id FROM observations WHERE id = $1 AND project_id = $2 AND team_id = $3',\n      [input.observationId, input.projectId, input.teamId]\n    );\n    if (!observation) {\n      throw new Error('observation_id does not exist');\n    }\n\n    const agentEventId = input.sourceType === 'agent_event'\n      ? input.agentEventId ?? input.sourceId\n      : null;\n\n    if (input.sourceType === 'agent_event') {\n      if (agentEventId !== input.sourceId) {\n        throw new Error('agent_event source_id must equal agent_event_id');\n      }\n      await assertAgentEventOwnership(this.client, input.sourceId, input.projectId, input.teamId);\n    } else if (input.sourceType === 'session_summary' && !input.generationJobId) {\n      await assertSessionOwnership(this.client, input.sourceId, input.projectId, input.teamId);\n    } else if (input.sourceType === 'observation_reindex' && !input.generationJobId) {\n      await assertObservationOwnership(this.client, input.sourceId, input.projectId, input.teamId);\n    }\n    if (input.generationJobId) {\n      await assertGenerationJobMatchesSource(this.client, {","sourceCodeStart":201,"sourceCodeEnd":237,"githubUrl":"https://github.com/thedotmack/claude-mem/blob/d768ba364302d12b76e69e4f021f0bb1d2d50ed6/src/storage/postgres/observations.ts#L201-L237","documentation":"Thrown by PostgresObservationSourcesRepository.addSource. It first checks that the target observation exists within (observationId, projectId, teamId). If no row is returned, the observation you are trying to attach a source to is not in scope (missing, wrong tenant, or deleted).","triggerScenarios":"Calling addSource() with an observationId that is not present in observations for the supplied project/team. The observation may belong to another tenant or may have never been created.","commonSituations":"Adding a source before creating the observation; cross-tenant id reuse; observation deleted by a cleanup job; using a source id instead of an observation id.","solutions":["Create the observation first (repository.create on PostgresObservationRepository) and use its returned id.","Resolve the observation via getByIdForScope before calling addSource; fail fast with a clearer message.","Confirm projectId/teamId match the observation's owner tenant."],"exampleFix":"// before\nawait sources.addSource({ observationId, projectId, teamId, sourceType:'agent_event', sourceId: eventId });\n// after\nconst obs = await observations.create({ projectId, teamId, content, ... });\nawait sources.addSource({ observationId: obs.id, projectId, teamId, sourceType:'agent_event', sourceId: eventId });","handlingStrategy":"validation","validationCode":"const obs = await observations.getByIdForScope({ id: observationId, projectId, teamId });\nif (!obs) throw new Error(`observation ${observationId} not in scope`);","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always create the parent observation before attaching sources.","Keep observation and source creation in the same transaction."],"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"}