thedotmack/claude-mem · error · Error
observation_reindex source_id must belong to project_id and…
Error message
observation_reindex source_id must belong to project_id and team_id
What it means
For 'observation_reindex' sources without a generationJobId, assertObservationOwnership verifies the sourceId refers to an existing observation row in the same project and team. The id is expected to point at an observations row; if it does not, reindex provenance cannot be established and the error is thrown.
Solutions
- Confirm sourceId is an observations id visible with the given projectId/teamId.
- Re-create the observation if it was deleted, or skip reindexing it.
- Ensure the reindex job reads ids and tenant ids from the same database it writes to.
Example fix
// before
await repo.addSource({ sourceType: 'observation_reindex', sourceId: sessionId, ... });
// after
await repo.addSource({ sourceType: 'observation_reindex', sourceId: observation.id, ... }); Defensive patterns
Strategy: validation
Validate before calling
if (sourceType === 'observation_reindex' && !generationJobId) {
const ok = await db.oneOrNone(
'SELECT 1 FROM observations WHERE id = $1 AND project_id = $2 AND team_id = $3',
[sourceId, projectId, teamId]
);
if (!ok) throw new Error(`reindex source ${sourceId} is not an in-scope observation`);
} Try / catch
try {
await repo.addSource(input);
} catch (e) {
if (e instanceof Error && e.message === 'observation_reindex source_id must belong to project_id and team_id') {
logger.warn('skipping reindex of missing observation', { id: input.sourceId });
return null;
}
throw e;
} Prevention
- For reindex sources, sourceId must be an observations id — double-check the field you pass.
- Re-list observations and reindex in the same run so ids cannot go stale.
- Run reindex jobs against the same database the ids were read from.
When it happens
Trigger: addSource with sourceType='observation_reindex', no generationJobId, and sourceId set to an id that is not an observations row in scope (a session id, an agent event id, a deleted observation, or wrong tenant).
Common situations: Reindex jobs that pass the wrong id field; observations deleted between listing and reindexing; running the reindex against a different database than the one the ids came from.
Understand the failure class
Background: Record Not Found Errors: "not found", RecordNotFound, and "was not found" — what they mean and how to fix them — this error's family across 28 libraries.
Related errors
- agent_event_id must belong to project_id and team_id
- generation_job_id must belong to project_id and team_id
- observation_id does not exist
- agent_event source_id must belong to project_id and team_id
- agent_event source_id must equal agent_event_id
AI-assisted analysis of thedotmack/claude-mem@d8bc9755e7 (2026-09-17).
Data as JSON: /api/errors/ca3b1e9dc4b55c05.
Report an issue: GitHub.
Appendix: source
Thrown at src/storage/postgres/observations.ts:388
);
if (!row) {
throw new Error('agent_event_id must belong to project_id and team_id');
}
}
async function assertObservationOwnership(
client: PostgresQueryable,
observationId: string,
projectId: string,
teamId: string
): Promise<void> {
const row = await queryOne<{ id: string }>(
client,
'SELECT id FROM observations WHERE id = $1 AND project_id = $2 AND team_id = $3',
[observationId, projectId, teamId]
);
if (!row) {
throw new Error('observation_reindex source_id must belong to project_id and team_id');
}
}
function mapObservationRow(row: ObservationRow): PostgresObservation {
return {
id: row.id,
projectId: row.project_id,
teamId: row.team_id,
serverSessionId: row.server_session_id,
kind: row.kind,
content: row.content,
generationKey: row.generation_key,
metadata: toJsonObject(row.metadata),
embedding: row.embedding,
createdByJobId: row.created_by_job_id,
createdAtEpoch: toEpoch(row.created_at),
updatedAtEpoch: toEpoch(row.updated_at)
};View on GitHub (pinned to d8bc9755e7)