thedotmack/claude-mem · warning

quota_exceeded

quota_exceeded

Error message

Monthly ${opts.kind} quota reached (${opts.cap})

What it means

402 Payment Required from the monthly quota middleware: month-to-date usage of the given kind for the team (summed since monthStartUtc) has reached opts.cap, so further requests are refused until the calendar month rolls over. The body includes used and cap so clients can compute remaining headroom; unlike the rate limiter this is not time-retryable within the month.

Source

Thrown at src/server/middleware/rate-limit.ts:77

      logger.warn('HTTP', 'rate limit check failed; allowing request (fail open)', {
        error: error instanceof Error ? error.message : String(error),
      });
      return next();
    }
  };
}

/** Checks month-to-date usage against the cap and answers 402 / next(). */
async function enforceMonthlyQuota(
  repo: PostgresUsageRepository,
  opts: { kind: string; cap: number },
  teamId: string,
  res: Response,
  next: NextFunction,
): Promise<Response | void> {
  const used = await repo.total({ teamId, kind: opts.kind, since: monthStartUtc(new Date()) });
  if (used >= opts.cap) {
    return res.status(402).json({
      error: 'quota_exceeded',
      message: `Monthly ${opts.kind} quota reached (${opts.cap})`,
      used,
      cap: opts.cap,
    });
  }
  return next();
}

/** Monthly per-team quota on a usage `kind` (e.g. 'request'). 402 when reached. */
export function requireMonthlyQuota(pool: PostgresPool, opts: { kind: string; cap: number }): RequestHandler {
  const repo = new PostgresUsageRepository(pool);
  return async (req: Request, res: Response, next: NextFunction) => {
    const teamId = req.authContext?.teamId;
    if (!teamId) return next();
    try {
      return await enforceMonthlyQuota(repo, opts, teamId, res, next);
    } catch (error) {

View on GitHub (pinned to e2d1df569a)

Solutions

  1. Raise the cap for the team/kind server-side if the usage is legitimate.
  2. Reduce counted usage: batch events (fewer metered requests) and drop generate=true where observations are not needed.
  3. Queue work client-side and resume after the month boundary (UTC) when usage resets.
  4. Alert on used/cap ratio from the response body or usage endpoint before hitting the wall.
Defensive patterns

Strategy: fallback

Validate before calling

// Track headroom from the last 402 body (used/cap) or a usage endpoint
function quotaHeadroom(used: number, cap: number): number {
  return cap - used;
}
if (quotaHeadroom(used, cap) < events.length) {
  return queueForNextMonth(events); // local spool, resume at UTC month start
}

Type guard

interface QuotaBody { error: string; used: number; cap: number }
function isQuotaExceeded(res: Response, body: unknown): body is QuotaBody {
  return res.status === 402 && typeof body === 'object' && body !== null &&
    (body as QuotaBody).error === 'quota_exceeded';
}

Try / catch

const res = await fetch(url, init);
if (res.status === 402) {
  const body = await res.json();
  if (isQuotaExceeded(res, body)) {
    await spoolForNextMonth(body); // do NOT retry within the month
  }
}

Prevention

When it happens

Trigger: Team's counted requests for the month hit the configured cap and any further metered call returns 402 with used >= cap; heavy batch ingestion early in the month exhausting the budget; quota cap lowered while usage already above it.

Common situations: Free-tier teams hitting monthly request caps mid-month; a runaway loop burning quota; ops reduced a cap retroactively and every team above it starts failing.

Related errors


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