thedotmack/claude-mem · error · Error

Cannot process observations: memorySessionId not yet capture

Error message

Cannot process observations: memorySessionId not yet captured. This session may need to be reinitialized.

What it means

Thrown by processObservationMessage when an ingest/observation message arrives for an ActiveSession whose memorySessionId has not yet been captured. memorySessionId is set during session initialization from the provider's first response; downstream observation processing needs it to scope the prompt. The guard prevents building an observation prompt against an unanchored session.

Source

Thrown at src/services/worker/OpenAICompatibleProvider.ts:202

        sessionId: session.sessionDbId, model
      });
    }
  }

  private async processObservationMessage(
    session: ActiveSession,
    message: { prompt_number?: number; tool_name?: string; tool_input?: unknown; tool_response?: unknown; cwd?: string },
    worker: WorkerRef | undefined,
    config: TConfig,
    originalTimestamp: number | null,
    lastCwd: string | undefined
  ): Promise<void> {
    if (message.prompt_number !== undefined) {
      session.lastPromptNumber = message.prompt_number;
    }

    if (!session.memorySessionId) {
      throw new Error('Cannot process observations: memorySessionId not yet captured. This session may need to be reinitialized.');
    }

    const obsPrompt = buildObservationPrompt({
      id: 0,
      tool_name: message.tool_name!,
      tool_input: JSON.stringify(message.tool_input),
      tool_output: JSON.stringify(message.tool_response),
      created_at_epoch: originalTimestamp ?? Date.now(),
      cwd: message.cwd
    });
    const responseContext = snapshotResponseContext(session);

    session.conversationHistory.push({ role: 'user', content: obsPrompt });
    session.lastPromptSentAt = Date.now();
    session.lastGeneratorSource = 'ingest';
    const obsResponse = await this.query(session.conversationHistory, config);

    let tokensUsed = 0;

View on GitHub (pinned to d768ba3643)

Solutions

  1. Reinitialize the session so the init handshake captures memorySessionId before observations are processed.
  2. Check worker logs for 'Empty <provider> init response - session may lack context' which indicates why the id was never set.
  3. Verify the session row in the DB has a non-null memory_session_id; if lost, restart the worker to trigger re-init.
  4. If reproducing in tests, ensure the provider mock returns a session_id in the init response before queueing observation messages.

Example fix

// before: observation queued before init resolves
await provider.processObservationMessage(session, msg, worker, config, ts, cwd);

// after: ensure memorySessionId captured first
if (!session.memorySessionId) {
  await provider.initializeSession(session, model, config);
}
await provider.processObservationMessage(session, msg, worker, config, ts, cwd);
Defensive patterns

Strategy: validation

Validate before calling

// Before calling observation processing, ensure the session is anchored
function isSessionReadyForObservations(session: ActiveSession): boolean {
  return typeof session.memorySessionId === 'string' && session.memorySessionId.length > 0;
}
if (!isSessionReadyForObservations(session)) {
  await provider.initializeSession(session, model, config);
}

Type guard

function hasMemorySessionId(s: ActiveSession): s is ActiveSession & { memorySessionId: string } {
  return typeof s.memorySessionId === 'string' && s.memorySessionId.length > 0;
}

Try / catch

try {
  await provider.processObservationMessage(session, msg, worker, config, ts, cwd);
} catch (err) {
  if (err instanceof Error && /memorySessionId not yet captured/.test(err.message)) {
    logger.warn('SDK', 'Observation skipped — session not initialized, reinitializing', { id: session.sessionDbId });
    await provider.initializeSession(session, model, config);
    return; // re-queue or drop
  }
  throw err;
}

Prevention

When it happens

Trigger: A tool observation message is enqueued and dispatched to processObservationMessage before session initialization completed (or after it failed silently). Concretely: session.memorySessionId is null/undefined when the worker drains the observation queue.

Common situations: Worker restart mid-session where in-memory state was rebuilt without the captured id; init response returned empty content (logger.error 'Empty ... init response') so session_id was never recorded; a race where the observation arrives during the init handshake; session restored from DB but the memorySessionId column was null.

Related errors


AI-assisted analysis of thedotmack/claude-mem@d768ba3643 (2026-08-12). Data as JSON: /api/errors/0f1ea5b456b9eb90. Report an issue: GitHub.