thedotmack/claude-mem · error · Error
agent_event source_id must equal agent_event_id
Error message
agent_event source_id must equal agent_event_id
What it means
When sourceType is 'agent_event', the sourceId is required to be the agent event's ID: the resolved agentEventId (explicit agentEventId ?? sourceId) must equal input.sourceId. Passing a different value for sourceId and agentEventId is contradictory, so addSource throws before any database work.
Solutions
- Set sourceId to the agent event's id whenever sourceType is 'agent_event'.
- Omit agentEventId entirely (it defaults from sourceId) instead of passing a second id.
- If you intended a non-agent-event source, change sourceType to the matching type ('manual', 'session_summary', etc.).
Example fix
// before
await repo.addSource({ sourceType: 'agent_event', sourceId: sessionId, agentEventId: eventId, ... });
// after
await repo.addSource({ sourceType: 'agent_event', sourceId: eventId, ... }); Defensive patterns
Strategy: validation
Validate before calling
if (sourceType === 'agent_event' && sourceId !== (agentEventId ?? sourceId)) {
throw new Error('agent_event addSource requires sourceId === agentEventId');
} Type guard
function isConsistentAgentEventSource(input: { sourceType: string; sourceId: string; agentEventId?: string | null }): boolean {
return input.sourceType !== 'agent_event' || (input.agentEventId ?? input.sourceId) === input.sourceId;
} Try / catch
try {
await repo.addSource(input);
} catch (e) {
if (e instanceof Error && e.message === 'agent_event source_id must equal agent_event_id') {
throw new Error(`bad addSource call: sourceId=${input.sourceId} agentEventId=${input.agentEventId}`);
}
throw e;
} Prevention
- For agent_event sources, only pass sourceId and let agentEventId default from it.
- Never reuse addSource input objects across different sourceType values.
- Add a unit test asserting agent-event sources always use the event id as sourceId.
When it happens
Trigger: Calling addSource with sourceType='agent_event' and both agentEventId and sourceId supplied where agentEventId !== sourceId; e.g. passing the observation id or a session id as sourceId while supplying the real event id in agentEventId.
Common situations: Copy-paste of a manual/session_summary addSource call changed to 'agent_event' without updating sourceId; wrappers that thread distinct ids into both fields; unit tests reusing fixtures from other source types.
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
- generation_job_id agent_event_id must match observation…
- agent_event source_id must belong to project_id and team_id
- audit log insert failed
- cannot process observation generation job after…
AI-assisted analysis of thedotmack/claude-mem@d8bc9755e7 (2026-09-17).
Data as JSON: /api/errors/bbc4cf804be63a5f.
Report an issue: GitHub.
Appendix: source
Thrown at src/storage/postgres/observations.ts:228
generationJobId?: string | null;
metadata?: JsonObject;
}): Promise<PostgresObservationSource> {
const observation = await queryOne<{ id: string }>(
this.client,
'SELECT id FROM observations WHERE id = $1 AND project_id = $2 AND team_id = $3',
[input.observationId, input.projectId, input.teamId]
);
if (!observation) {
throw new Error('observation_id does not exist');
}
const agentEventId = input.sourceType === 'agent_event'
? input.agentEventId ?? input.sourceId
: null;
if (input.sourceType === 'agent_event') {
if (agentEventId !== input.sourceId) {
throw new Error('agent_event source_id must equal agent_event_id');
}
await assertAgentEventOwnership(this.client, input.sourceId, input.projectId, input.teamId);
} else if (input.sourceType === 'session_summary' && !input.generationJobId) {
await assertSessionOwnership(this.client, input.sourceId, input.projectId, input.teamId);
} else if (input.sourceType === 'observation_reindex' && !input.generationJobId) {
await assertObservationOwnership(this.client, input.sourceId, input.projectId, input.teamId);
}
if (input.generationJobId) {
await assertGenerationJobMatchesSource(this.client, {
generationJobId: input.generationJobId,
projectId: input.projectId,
teamId: input.teamId,
sourceType: input.sourceType,
sourceId: input.sourceId,
agentEventId
});
}
View on GitHub (pinned to d8bc9755e7)