thedotmack/claude-mem · warning

Aborting session for quota guard: ${decision.reason}

Error message

Aborting session for quota guard: ${decision.reason}

What it means

When the SDK emits a rate_limit system message, claude-mem stores the snapshot and consults shouldAbortForQuota(). API-key auth never aborts (per-call billing is pre-authorized), but subscription/OAuth auth aborts when a window (five_hour, seven_day_opus, seven_day_sonnet, seven_day, overage) crosses its utilization threshold or the provider explicitly reports the bucket exhausted/rejected. This warning fires and the observer session is aborted via its AbortController.

Source

Thrown at src/services/worker/ClaudeProvider.ts:319

          // session is out of usage too. set() dedupes: one event per
          // exhausted window, not one per observer request against the wall.
          if (globalRateLimitStore.set(info)) {
            logger.warn('SDK', 'Subscription usage limit hit', {
              sessionDbId: session.sessionDbId,
              window: info.rateLimitType,
              overageStatus: info.overageStatus,
            });
            captureEvent('usage_limit_hit', {
              ...buildUsageLimitHitProps(info),
              ide: session.platformSource,
              provider: 'claude',
              observed_model: session.observedModel,
              observed_billing: session.observedBilling,
            });
          }
          const decision = shouldAbortForQuota(authMethod, globalRateLimitStore);
          if (decision.abort) {
            logger.warn('SDK', `Aborting session for quota guard: ${decision.reason}`, {
              sessionDbId: session.sessionDbId,
              window: decision.window,
              authMethod,
            });
            session.abortReason = `quota:${decision.window ?? 'unknown'}`;
            try {
              session.abortController.abort();
            } catch {
              // best-effort
            }
            break;
          }
        }

        if (message.session_id && message.session_id !== session.memorySessionId) {
          const previousId = session.memorySessionId;
          session.memorySessionId = message.session_id;
          this.dbManager.getSessionStore().ensureMemorySessionIdRegistered(

View on GitHub (pinned to 8bc631a71a)

Solutions

  1. Wait for the rate-limit window to reset (the guard deliberately stops before burning the last few percent)
  2. Switch the observer to API-key auth so per-call spend is authorized and the quota guard never aborts
  3. Reduce consumption: lower observer frequency, close unneeded sessions, or free the busy window before resuming

Example fix

# switch observer to API-key auth so the subscription quota guard does not abort
# ~/.claude-mem/.env
ANTHROPIC_AUTH_METHOD=api_key
ANTHROPIC_API_KEY=sk-ant-...
Defensive patterns

Strategy: validation

Validate before calling

import { shouldAbortForQuota } from './RateLimitStore.js';

function guardBeforeObserverRun(authMethod: string, store: RateLimitStore): void {
  const decision = shouldAbortForQuota(authMethod, store);
  if (decision.abort) {
    throw new Error(`skipping observer run — ${decision.reason}`);
  }
}

Type guard

function isApiKeyAuth(authMethod: string): boolean {
  return authMethod === 'api_key' || authMethod.startsWith('API key');
}

Prevention

When it happens

Trigger: Subscription auth with the five-hour window near its utilization threshold; a seven-day Opus/Sonnet bucket reported as rejected; overage window exhausted; a reset due within the 15-minute grace buffer while utilization is above the floor.

Common situations: Heavy parallel Claude Code plus observer usage on a Pro/Max plan near quota; weekend sprints exhausting the five-hour window; the observer's background summarization tipping an already-high bucket.

Related errors


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