thedotmack/claude-mem · warning

session_not_found

session_not_found

Error message

session_not_found

What it means

404 from the compat summarize route when the endSession pipeline resolves to no session (result.session is null). The adapter looked up the session by contentSessionId within the key's team/project and either found nothing or the end operation could not materialize a session row; the response keeps the legacy shape { status: 'not_found', reason: 'session_not_found' }.

Source

Thrown at src/server/compat/SessionsSummarizeAdapter.ts:122

      teamId,
      projectId,
      contentSessionId: data.contentSessionId,
      platformSource,
      agentId: null,
      agentType: null,
    });

    const result = await this.options.endSession.end({
      sessionId: session.id,
      projectId,
      teamId,
      source: 'http_post_api_sessions_summarize',
      apiKeyId: req.authContext?.apiKeyId ?? null,
      actorId: null,
      sourceAdapter: 'claude-code-compat',
    });
    if (!result.session) {
      res.status(404).json({ status: 'not_found', reason: 'session_not_found' });
      return;
    }
    res.json({
      status: 'queued',
      sessionId: session.id,
      serverSessionId: session.id,
      generationJobId: result.outbox?.id ?? null,
      transport: result.enqueueState,
    });
  }

  private asyncHandler(fn: (req: Request, res: Response) => Promise<void> | void) {
    return (req: Request, res: Response, next: (err?: unknown) => void): void => {
      Promise.resolve(fn(req, res)).catch(next);
    };
  }
}

View on GitHub (pinned to e2d1df569a)

Solutions

  1. Verify the contentSessionId was actually ingested: check that events for it were accepted (201 from /v1/events) under the same team/project as the key.
  2. Confirm the API key's project scope matches the project that owns the session.
  3. Make summarize idempotent on the client: treat 404 session_not_found as terminal, not retryable.
  4. If the session should exist, query the sessions/events listing for that team to see whether it was ended or never created.
Defensive patterns

Strategy: validation

Validate before calling

// Confirm ingestion before summarizing
const created = await postJson('/v1/events', {
  projectId, contentSessionId: sid,
  type: 'session.start', // per schema
});
if (created.status !== 201 && created.status !== 200) {
  throw new Error(`session ${sid} not ingestible; skipping summarize`);
}

Type guard

interface NotFoundBody { status: string; reason: string }
function isSessionNotFound(body: unknown): body is NotFoundBody {
  return typeof body === 'object' && body !== null &&
    (body as NotFoundBody).status === 'not_found' && (body as NotFoundBody).reason === 'session_not_found';
}

Try / catch

const res = await summarize(sid);
if (res.status === 404) {
  const body = await res.json();
  if (isSessionNotFound(body)) return; // terminal: session absent under this scope
}

Prevention

When it happens

Trigger: POST /api/sessions/summarize with a contentSessionId never created in that team/project; summarizing a session whose id belongs to a different project than the key's scope; calling summarize twice where the first call ended and removed/flagged the session so a second call cannot resolve it.

Common situations: Client regenerates session ids per run and summarizes an id from a stale run; key's projectId does not match the project that ingested the session's events; environment mismatch (test key against prod data or vice versa).

Related errors


AI-assisted analysis of thedotmack/claude-mem@e2d1df569a (2026-08-20). Data as JSON: /api/errors/55137969ce70f22c. Report an issue: GitHub.