thedotmack/claude-mem · error · Error
generation_job_id agent_event_id must match observation…
Error message
generation_job_id agent_event_id must match observation source
What it means
For sourceType 'agent_event', the generation job row's agent_event_id must match the resolved agentEventId of the observation source being linked. A mismatch means the job was run against a different agent event than the one this source points at, so the link is rejected to keep provenance exact.
Solutions
- Compare the job row's agent_event_id with the event id you pass; use the job created for that exact event.
- Re-run generation for the correct agent event and link the new job id.
- Fix any parallel/retry logic that pairs jobs to events by index instead of by id.
Example fix
// before
await repo.addSource({ sourceType: 'agent_event', sourceId: evt.id, generationJobId: jobForOtherEvent.id, ... });
// after
const job = await db.one(
'SELECT id FROM observation_generation_jobs WHERE agent_event_id = $1', [evt.id]
);
await repo.addSource({ sourceType: 'agent_event', sourceId: evt.id, generationJobId: job.id, ... }); Defensive patterns
Strategy: validation
Validate before calling
const job = await db.one(
'SELECT agent_event_id FROM observation_generation_jobs WHERE id = $1', [generationJobId]
);
if (job.agent_event_id !== agentEventId) {
throw new Error(`job ${generationJobId} belongs to event ${job.agent_event_id}, not ${agentEventId}`);
} Try / catch
try {
await repo.addSource(input);
} catch (e) {
if (e instanceof Error && e.message === 'generation_job_id agent_event_id must match observation source') {
logger.warn('agent_event/job mismatch', { jobId: input.generationJobId });
return null;
}
throw e;
} Prevention
- In concurrent generation loops, key results by agent event id, not completion order.
- Store the agentEventId on the job result object and pass it through unchanged.
- Add a regression test that generates observations for two events in parallel and links them.
When it happens
Trigger: addSource with sourceType='agent_event', a generationJobId whose row stores a different agent_event_id than the source's agent event id — e.g. two agent events handled by swapped job variables.
Common situations: Parallel generation of observations for many agent events where job results are paired to the wrong event; reprocessing events in a different order; null vs non-null agent_event_id between job and source.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- agent_event_id must belong to project_id and team_id
- agent_event source_id must equal agent_event_id
- generation_job_id source model must match observation source
- agent_event source_id must belong to project_id and team_id
- audit log insert failed
AI-assisted analysis of thedotmack/claude-mem@d8bc9755e7 (2026-09-17).
Data as JSON: /api/errors/7b9f2507124fff5a.
Report an issue: GitHub.
Appendix: source
Thrown at src/storage/postgres/observations.ts:356
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) {
throw new Error('agent_event_id must belong to project_id and team_id');
}
}View on GitHub (pinned to d8bc9755e7)