Playbook: Queue failures — Claude weekly usage limit
Trigger
Multiple queue rows with failure_reason=timeout and retry_count=max_retries (permanently failed),
worker logs showing:
[spawn] PID=XXXXXX issue=#N ...
You've hit your weekly limit · resets 3am (UTC)
Occurs when a claude-runner-N subscription hits its Claude Code weekly token limit
mid-dispatch-wave. The limit resets every Monday at 03:00 UTC.
Confirm
# On bms-4 — check spawn logs for the weekly limit message
grep -r "weekly limit" /var/log/p24-infra-workers/ | tail -20
# Check queue rows
# (from Windows dev machine, via Supabase REST or psql on bms-4)
# status=failed + failure_reason=timeout + error_message contains "timed out"What happens
- Claude Code starts (
spawn-worker.shspawned OK, PID assigned) - Claude Code immediately outputs
You've hit your weekly limit · resets 3am (UTC)and exits - Before fix (pre-PR #2185): spawn-worker.sh didn’t detect this → returned exit 0 → dispatcher
marked job as running → reset_stale_workers marked it
timeoutafter heartbeat gap → retried 2 more times → permanently failed (retry_count=2/2) - After fix (PR #2185): spawn-worker.sh detects the message within 5s post-spawn → exits 5 (subscription blocked) → dispatcher tries next subscription user immediately
Fix (after PR #2185 deployed)
The weekly limit is self-healing — it resets at 03:00 UTC Monday. No manual action needed for the queue; the meta-dispatcher will automatically re-queue permanently-failed issues on the next dispatch cycle (failed rows don’t block re-dispatch).
If you need to act immediately (e.g. mid-week limit hit on both users):
- Check which
claude-runner-Nusers have limits hit:# On bms-4 for u in claude-runner claude-runner-2 claude-runner-3; do echo "=== $u ===" su - $u -s /bin/bash -c "cat ~/.claude/sub-status.json 2>/dev/null | python3 -c 'import json,sys; d=json.load(sys.stdin); print(d.get(\"usage_pct\"), d.get(\"reset_at\"))'" 2>/dev/null || echo "no status" done - If all users exhausted: wait for reset, no further action (jobs re-dispatch automatically)
- Permanently-failed rows (retry=2/2) are NOT re-queued by retry-worker — but the meta-dispatcher re-queues the underlying GitHub issues on its next run (if still In Progress milestone)
Prevention / detection
spawn-worker.shpost-spawn check (PR #2185) catches the message and exits 5 → next-user retrycheck-sub-usage.pyruns as cron and writes~/.claude/sub-status.json— pre-spawn check reads this; may be stale by ≤cron-interval- Grafana panel “Worker Queue — Failed by reason” shows spike in
timeoutfailures - Mezmo logs:
app:spawn-worker level:WARN "weekly_limit_post_spawn"
nc-alert-batch implementation_error (related bug, also fixed in PR #2185)
Trigger: queue rows with job_type=nc-alert-batch, failure_reason=implementation_error,
error_message="spawn failed exit=1".
Root cause: spawn-worker.sh job_type validation list was missing nc-alert-batch → exit 1
on every dispatch attempt.
Fix: PR #2185 adds nc-alert-batch to the allowlist. If stale rows remain after deploy:
# Cancel duplicate older rows, reset newest to queued
# Use Supabase PATCH on dev_r_worker_queue — set only the newest to status=queued,retry_count=0
# Cancel duplicates with status=cancelled,failure_reason=stale_duplicate