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
- 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.
- Check the full abort reason in worker logs (category is only the prefix before ':') to confirm whether quota or auth fired.
- If quota pauses recur, reduce observation/summarization frequency in claude-mem settings to lower API burn.
- 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
- Monitor provider quota headroom and alert before exhaustion instead of at abort time.
- Refresh OAuth/API credentials on a schedule before expiry rather than after deauth.
- Treat reason strings with 'quota:'/'auth:' prefixes as resumable in your own session-management code.
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
- missing_api_key
- Transcript path missing or file does not exist: ${transcript
- Transcript file exists but is empty: ${transcriptPath}
- auth_invalid
- Invalid mode inheritance: ${modeId}. Only one level of inher
AI-assisted analysis of thedotmack/claude-mem@e2d1df569a (2026-08-20).
Data as JSON: /api/errors/a5ea1ce0f16473ce.
Report an issue: GitHub.