thedotmack/claude-mem · warning

Generator paused for ${abortCategory}; preserving buffered w

Error message

Generator paused for ${abortCategory}; preserving buffered work

What it means

When a session's SDK generator loop exits, GeneratorExitHandler strips the abort reason to its category (the prefix before ':'). For 'quota' or 'auth' categories it deliberately skips completionHandler.finalizeSession and returns early, preserving the session's buffered messages (pendingCount is logged) so no in-flight work is lost. All other reasons fall through to normal finalization.

Source

Thrown at src/services/worker/session/GeneratorExitHandler.ts:46

export async function handleGeneratorExit(
  session: ActiveSession,
  reason: ActiveSession['abortReason'],
  deps: GeneratorExitDependencies
): Promise<void> {
  const { sessionManager, completionHandler } = deps;
  const sessionDbId = session.sessionDbId;

  const tracked = getSdkProcessForSession(sessionDbId);
  if (tracked && !tracked.process.killed && tracked.process.exitCode === null) {
    await ensureSdkProcessExit(tracked, 5000);
  }

  session.generatorPromise = null;
  session.currentProvider = null;

  const abortCategory = (reason ?? '').split(':')[0];
  if (abortCategory === 'quota' || abortCategory === 'auth') {
    logger.warn('SESSION', `Generator paused for ${abortCategory}; preserving buffered work`, {
      sessionId: sessionDbId,
      pendingCount: sessionManager.getMessageBuffer().getPendingCount(sessionDbId),
    });
    return;
  }

  logger.info('SESSION', 'Generator exited — finalizing session', { sessionId: sessionDbId, reason });

  try {
    await completionHandler.finalizeSession(sessionDbId);
  } catch (e) {
    const normalized = e instanceof Error ? e : new Error(String(e));
    logger.error('SESSION', 'Finalization failed; forcing in-memory session removal', {
      sessionId: sessionDbId,
      reason
    }, normalized);
  } finally {
    sessionManager.removeSessionImmediate(sessionDbId);

View on GitHub (pinned to e2d1df569a)

Solutions

  1. Restore provider capacity: wait out the quota window or re-login to refresh credentials, then start a new session — buffered work is preserved, not lost.
  2. Check the full abort reason in worker logs (category is only the prefix before ':') to confirm whether quota or auth fired.
  3. If quota pauses recur, reduce observation/summarization frequency in claude-mem settings to lower API burn.
  4. Verify pendingCount in the log entry to confirm messages survived the pause; they flush when the session resumes or finalizes.

Example fix

// before
await completionHandler.finalizeSession(sessionDbId); // runs even on quota/auth aborts, discarding buffer

// after
const abortCategory = (reason ?? '').split(':')[0];
if (abortCategory === 'quota' || abortCategory === 'auth') {
  logger.warn('SESSION', `Generator paused for ${abortCategory}; preserving buffered work`, {
    sessionId: sessionDbId,
    pendingCount: sessionManager.getMessageBuffer().getPendingCount(sessionDbId),
  });
  return;
}
await completionHandler.finalizeSession(sessionDbId);
Defensive patterns

Strategy: fallback

Validate before calling

const abortCategory = (reason ?? '').split(':')[0];
if (abortCategory === 'quota' || abortCategory === 'auth') {
  // preserve buffer now, schedule resume when capacity returns
  sessionManager.getMessageBuffer().retain(sessionDbId);
  return;
}

Type guard

const isPreservingAbortCategory = (reason?: string | null): boolean =>
  ['quota', 'auth'].includes((reason ?? '').split(':')[0]);

Try / catch

try {
  await runGenerator(session);
} catch (e) {
  const reason = e instanceof Error ? e.message : String(e);
  if (isPreservingAbortCategory(reason)) return preserveBuffer(session);
  throw e;
}

Prevention

When it happens

Trigger: session.generatorPromise settles with a reason string like "quota: ..." (provider quota exhausted) or "auth: ..." (credentials rejected/expired); the handler awaits SDK process exit (5s), clears generatorPromise/currentProvider, then takes the early return before finalizeSession.

Common situations: Hitting the Anthropic API usage limit mid-session; OAuth token or API key expiring/rotating while a generator was running; provider-side deauth of long-lived worker sessions.

Related errors


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