Your morning plan died five days in a row with one repeated line: 'OAuth session expired and could not be refreshed.' Today you learn what that sentence actually means, why no amount of retrying could fix it, and why the alert wall stayed quiet instead of growing by five.
This is not hypothetical — it is the exact failure that killed plan-day from Jul 22 through Jul 26 (logs/plan-day.log lines ~1975 onward). The watchdog fired, the retry loop ran all 3 attempts, the network was fine — and every attempt failed identically, because the one thing the job needed was a human with a browser. Meanwhile the new dedup ledger (shipped Jul 26) correctly held five failures to ONE Things task instead of five.
A program can prove its identity to Anthropic two ways. An **API key** is a long-lived credential — a string that works until you revoke it, billed per-token. An **OAuth session** is what you get when you 'log in with your Claude account' in a browser: a short-lived access token plus a refresh token that quietly mints new access tokens in the background. The `claude` CLI on your Mac uses the OAuth route, which is why headless runs ride on your Claude subscription instead of a separate API bill.
The catch: refresh only works while the refresh token itself is still valid. When it expires or gets invalidated (long idle stretches, a re-login elsewhere, a revocation), the CLI needs the full browser dance again — and a launchd job firing at 6:15am has no browser and no human. So it prints 'OAuth session expired and could not be refreshed' and exits 1. This is a fundamentally different failure class from a network blip: a retry loop fixes flakes, but retrying an auth failure just fails identically N times. That is exactly what your log shows — rc=1 on attempts 1, 2, and 3, every morning, five mornings straight.
Where it lives in your system: `PDB/scripts/run_plan_day.sh` wraps `claude -p` in a network-wait, a watchdog, and `run_with_retry` (3 attempts). All three guardrails are for *transient* failures; none can fix auth. The layer that behaved perfectly was the alert dedup ledger from commit d9b37fc — its `[alerts] deduped 'plan-day-fail' (×5, open since 2026-07-22)' line means: same outage, still open, no new task. One 🚨, not five. The fix was you opening an interactive session (which completed the login) — and this morning's run authenticated cleanly.
Forensics on your own log — the whole incident is readable in four greps:
cd ~/Claude/PDB
# 1. The failure signature — five mornings of it
grep -n 'OAuth session expired' logs/plan-day.log | head -6
# 2. Proof retries can't fix auth: all 3 attempts, same rc=1
grep -n 'attempt 3 failed' logs/plan-day.log | tail -3
# 3. The dedup ledger doing its job — one task, not five
grep -n "deduped 'plan-day-fail'" logs/plan-day.log | tail -1
# 4. This morning's recovery
grep -n 'Jul 27.*plan-day fire' logs/plan-day.log
A watchdog can restart a job and a retry can outlast a flake, but only a human can re-login — so the job's real duty is to fail loudly, once, and point at the fix.