thedotmack/claude-mem · error · Error
server_session_id must match the agent_event…
Error message
server_session_id must match the agent_event server_session_id
What it means
When creating a generation job with sourceType 'agent_event' and an explicit serverSessionId, validateSource checks that the referenced agent_event's stored server_session_id matches the caller-supplied one. If the event is already bound to a different session, the mismatch is rejected. This keeps job/session/event linkage consistent.
Solutions
- Pass the same serverSessionId that the agent_event is bound to (read it from the event row first)
- Omit serverSessionId if you do not need to assert session ownership on the job
- Use an event id belonging to the current session instead of an older one
- Verify the event was not re-bound to a different session between fetch and create
Example fix
// before
await jobs.create({ sourceType: 'agent_event', sourceId: eventId, serverSessionId: currentSessionId });
// after
const event = await eventsRepository.getById(eventId);
await jobs.create({ sourceType: 'agent_event', sourceId: eventId, serverSessionId: event.serverSessionId ?? currentSessionId }); Defensive patterns
Strategy: validation
Validate before calling
if (input.serverSessionId) {
const ev = await client.query('SELECT server_session_id FROM agent_events WHERE id=$1', [input.sourceId]);
if (ev.rows[0]?.server_session_id && ev.rows[0].server_session_id !== input.serverSessionId) {
throw new Error('serverSessionId does not match event');
}
} Try / catch
try {
await jobs.create(input);
} catch (err) {
if (err instanceof Error && err.message.includes('server_session_id must match')) {
// fall back to the event's own session or drop serverSessionId and retry
await jobs.create({ ...input, serverSessionId: undefined });
} else throw err;
} Prevention
- Read the event's bound session id and pass that, or omit serverSessionId
- Avoid reusing event ids across session restarts
- Keep session ids flowing from the same source event stream
When it happens
Trigger: create() with sourceType 'agent_event', a serverSessionId provided, and the agent_event row's server_session_id is non-null and different from input.serverSessionId (the event is bound to another session).
Common situations: Caller passes the current session id while the event originated in an earlier session; a session restart changed ids but the caller reused a stale event id; race where the event was bound to a session after the caller read it.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- session_summary source_id must equal server_session_id
- agent_event source_id must belong to project_id and team_id
- observation_reindex source_id must belong to project_id and…
- Adapter rejected input
- agent_event_id must belong to project_id and team_id
AI-assisted analysis of thedotmack/claude-mem@d8bc9755e7 (2026-09-17).
Data as JSON: /api/errors/ff8967aecbe5d902.
Report an issue: GitHub.
Appendix: source
Thrown at src/storage/postgres/generation-jobs.ts:275
sourceId: string;
agentEventId?: string | null;
serverSessionId?: string | null;
}): Promise<void> {
await assertProjectOwnership(this.client, input.projectId, input.teamId);
if (input.sourceType === 'agent_event') {
const eventId = input.agentEventId ?? input.sourceId;
const row = await queryOne<{ id: string; server_session_id: string | null }>(
this.client,
'SELECT id, server_session_id FROM agent_events WHERE id = $1 AND project_id = $2 AND team_id = $3',
[eventId, input.projectId, input.teamId]
);
if (!row || input.sourceId !== eventId) {
throw new Error('agent_event source_id must belong to project_id and team_id');
}
if (input.serverSessionId) {
await assertSessionOwnership(this.client, input.serverSessionId, input.projectId, input.teamId);
if (row.server_session_id && row.server_session_id !== input.serverSessionId) {
throw new Error('server_session_id must match the agent_event server_session_id');
}
}
return;
}
if (input.sourceType === 'session_summary') {
const sessionId = input.serverSessionId ?? input.sourceId;
await assertSessionOwnership(this.client, sessionId, input.projectId, input.teamId);
if (input.sourceId !== sessionId) {
throw new Error('session_summary source_id must equal server_session_id');
}
return;
}
const observation = await queryOne<{ id: string }>(
this.client,
'SELECT id FROM observations WHERE id = $1 AND project_id = $2 AND team_id = $3',
[input.sourceId, input.projectId, input.teamId]View on GitHub (pinned to d8bc9755e7)