thedotmack/claude-mem · error

generation_job_id source model must match observation source

Error message

generation_job_id source model must match observation source

What it means

Thrown by assertGenerationJobMatchesSource after confirming the job exists in scope. It compares the job's stored source_type and source_id against the sourceType/sourceId supplied to addSource. A mismatch means the observation's source does not match the source the job was created from, so they cannot be linked.

Source

Thrown at src/storage/postgres/observations.ts:353

  const row = await queryOne<{
    id: string;
    source_type: string;
    source_id: string;
    agent_event_id: string | null;
  }>(
    client,
    `
      SELECT id, source_type, source_id, agent_event_id
      FROM observation_generation_jobs
      WHERE id = $1 AND project_id = $2 AND team_id = $3
    `,
    [input.generationJobId, input.projectId, input.teamId]
  );
  if (!row) {
    throw new Error('generation_job_id must belong to project_id and team_id');
  }
  if (row.source_type !== input.sourceType || row.source_id !== input.sourceId) {
    throw new Error('generation_job_id source model must match observation source');
  }
  if (input.sourceType === 'agent_event' && row.agent_event_id !== input.agentEventId) {
    throw new Error('generation_job_id agent_event_id must match observation source');
  }
}

async function assertAgentEventOwnership(
  client: PostgresQueryable,
  agentEventId: string,
  projectId: string,
  teamId: string
): Promise<void> {
  const row = await queryOne<{ id: string }>(
    client,
    'SELECT id FROM agent_events WHERE id = $1 AND project_id = $2 AND team_id = $3',
    [agentEventId, projectId, teamId]
  );
  if (!row) {

View on GitHub (pinned to d768ba3643)

Solutions

  1. Look up the job and use its source_type/source_id as the source for the observation.
  2. Create a dedicated job for the exact (sourceType, sourceId) before linking.
  3. Do not share one job id across different sources.

Example fix

// before
await sources.addSource({ observationId, projectId, teamId, sourceType:'session_summary', sourceId: sessionId, generationJobId: agentEventJobId });
// after
const job = await jobs.getByIdForScope({ id: generationJobId, projectId, teamId });
await sources.addSource({ observationId, projectId, teamId, sourceType: job.sourceType, sourceId: job.sourceId, generationJobId: job.id });
Defensive patterns

Strategy: validation

Validate before calling

const job = await jobs.getByIdForScope({ id: generationJobId, projectId, teamId });
if (job.sourceType !== sourceType || job.sourceId !== sourceId) throw new Error('source/job mismatch');

Type guard

function jobMatchesSource(job, input){ return job.sourceType===input.sourceType && job.sourceId===input.sourceId; }

Prevention

When it happens

Trigger: addSource with a generationJobId where the job's (source_type, source_id) differ from the (sourceType, sourceId) passed in. E.g. job created from agent_event X but you try to link a session_summary source.

Common situations: Mixing up jobs for different sources; reusing a job id across reprocessed sources; UI passing a default job id regardless of which source is being linked.

Related errors


AI-assisted analysis of thedotmack/claude-mem@d768ba3643 (2026-08-12). Data as JSON: /api/errors/62705560e62eaa79. Report an issue: GitHub.