thedotmack/claude-mem · error
server_session_id must belong to project_id and team_id
Error message
server_session_id must belong to project_id and team_id
What it means
Thrown by assertSessionOwnership (shared helper in utils.ts). It queries server_sessions by (id, project_id, team_id); a missing row means the server session is not in the project/team scope. Used wherever a serverSessionId must be validated against tenant boundaries.
Source
Thrown at src/storage/postgres/utils.ts:78
);
if (!row) {
throw new Error('project_id must belong to team_id');
}
}
export async function assertSessionOwnership(
client: PostgresQueryable,
serverSessionId: string,
projectId: string,
teamId: string
): Promise<void> {
const row = await queryOne<{ id: string }>(
client,
'SELECT id FROM server_sessions WHERE id = $1 AND project_id = $2 AND team_id = $3',
[serverSessionId, projectId, teamId]
);
if (!row) {
throw new Error('server_session_id must belong to project_id and team_id');
}
}
export function canonicalJson(value: unknown): string {
return JSON.stringify(sortJson(value));
}
export function deterministicKey(parts: readonly unknown[]): string {
const fingerprint = createHash('sha256')
.update(canonicalJson(parts))
.digest('hex');
return fingerprint;
}
function sortJson(value: unknown): unknown {
if (Array.isArray(value)) {
return value.map(sortJson);
}View on GitHub (pinned to d768ba3643)
Solutions
- Resolve the server session within scope before referencing it.
- Confirm the session was created under the same project/team.
- Use the id stored in server_sessions exactly.
Example fix
// before
await observations.create({ projectId, teamId, serverSessionId: staleId, content });
// after
const session = await serverSessions.getByIdForScope({ id: serverSessionId, projectId, teamId });
if (!session) throw new Error('session not in scope');
await observations.create({ projectId, teamId, serverSessionId, content }); Defensive patterns
Strategy: validation
Validate before calling
const session = await serverSessions.getByIdForScope({ id: serverSessionId, projectId, teamId });
if (!session) throw new Error('server_session not in scope'); Prevention
- Always scope session lookups by project+team.
- Discard cached session ids when the project context changes.
When it happens
Trigger: Passing a serverSessionId that does not exist under the given project/team to create()/validateSource() or any helper that calls assertSessionOwnership. Project ownership is usually validated separately first.
Common situations: Session id from another project/tenant, expired/purged session, stale cached id, or a derived session-group id being passed instead of the real server_session id.
Related errors
- server_session_id must match the agent_event server_session_
- observation_reindex source_id must belong to project_id and
- observation_id does not exist
- generation_job_id must belong to project_id and team_id
- agent_event_id must belong to project_id and team_id
AI-assisted analysis of thedotmack/claude-mem@d768ba3643 (2026-08-12).
Data as JSON: /api/errors/8a96bec8ab8a7a2f.
Report an issue: GitHub.