{"record":{"id":"ff8967aecbe5d902","repo":"thedotmack/claude-mem","slug":"server-session-id-must-match-the-agent-event-serve","errorCode":null,"errorMessage":"server_session_id must match the agent_event server_session_id","messagePattern":"server_session_id must match the agent_event server_session_id","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/storage/postgres/generation-jobs.ts","lineNumber":275,"sourceCode":"    sourceId: string;\n    agentEventId?: string | null;\n    serverSessionId?: string | null;\n  }): Promise<void> {\n    await assertProjectOwnership(this.client, input.projectId, input.teamId);\n    if (input.sourceType === 'agent_event') {\n      const eventId = input.agentEventId ?? input.sourceId;\n      const row = await queryOne<{ id: string; server_session_id: string | null }>(\n        this.client,\n        'SELECT id, server_session_id FROM agent_events WHERE id = $1 AND project_id = $2 AND team_id = $3',\n        [eventId, input.projectId, input.teamId]\n      );\n      if (!row || input.sourceId !== eventId) {\n        throw new Error('agent_event source_id must belong to project_id and team_id');\n      }\n      if (input.serverSessionId) {\n        await assertSessionOwnership(this.client, input.serverSessionId, input.projectId, input.teamId);\n        if (row.server_session_id && row.server_session_id !== input.serverSessionId) {\n          throw new Error('server_session_id must match the agent_event server_session_id');\n        }\n      }\n      return;\n    }\n\n    if (input.sourceType === 'session_summary') {\n      const sessionId = input.serverSessionId ?? input.sourceId;\n      await assertSessionOwnership(this.client, sessionId, input.projectId, input.teamId);\n      if (input.sourceId !== sessionId) {\n        throw new Error('session_summary source_id must equal server_session_id');\n      }\n      return;\n    }\n\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.sourceId, input.projectId, input.teamId]","sourceCodeStart":257,"sourceCodeEnd":293,"githubUrl":"https://github.com/thedotmack/claude-mem/blob/d8bc9755e74915e5c3b999181e10a67c889bce2a/src/storage/postgres/generation-jobs.ts#L257-L293","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","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"],"exampleFix":"// before\nawait jobs.create({ sourceType: 'agent_event', sourceId: eventId, serverSessionId: currentSessionId });\n// after\nconst event = await eventsRepository.getById(eventId);\nawait jobs.create({ sourceType: 'agent_event', sourceId: eventId, serverSessionId: event.serverSessionId ?? currentSessionId });","handlingStrategy":"validation","validationCode":"if (input.serverSessionId) {\n  const ev = await client.query('SELECT server_session_id FROM agent_events WHERE id=$1', [input.sourceId]);\n  if (ev.rows[0]?.server_session_id && ev.rows[0].server_session_id !== input.serverSessionId) {\n    throw new Error('serverSessionId does not match event');\n  }\n}","typeGuard":null,"tryCatchPattern":"try {\n  await jobs.create(input);\n} catch (err) {\n  if (err instanceof Error && err.message.includes('server_session_id must match')) {\n    // fall back to the event's own session or drop serverSessionId and retry\n    await jobs.create({ ...input, serverSessionId: undefined });\n  } else throw err;\n}","preventionTips":["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"],"tags":["postgres","validation","session"],"backgroundTag":"type-mismatch","analyzedSha":"d8bc9755e74915e5c3b999181e10a67c889bce2a","analyzedAt":"2026-09-17T16:40:26.182Z","contentChangedAt":"2026-09-17T16:40:26.182Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}