[BUG] Literal "HERMES.md" in git commit messages triggers 400 "out of extra usage" on Max OAuth (content filter false-positive misclassified as quota error)
Summary
A literal HERMES.md string (uppercase + dot + md, case-sensitive) appearing anywhere in git log of the current working directory causes Claude Code on a Claude Max OAuth plan to return:
API Error: 400 {"type":"error","error":{"type":"invalid_request_error","message":"You're out of extra usage. Add more at claude.ai/settings/usage and keep going."}}
The error message is misleading — the Max plan has plenty of quota. This appears to be a server-side content filter false-positive (likely matching the canonical doc filename of an external AI project) that misroutes the request to the disabled "extra usage" lane.
Minimal Reproduction (10 lines, deterministic)
mkdir /tmp/repro-hermes && cd /tmp/repro-hermes
git init -q
echo a > a.txt && git add .
git commit -m "HERMES.md" # exact case + .md is the trigger
claude
# > hi
# Result: API Error 400 "You're out of extra usage..."
Removing .git/ or rewording the commit message makes the error disappear instantly.
Trigger Specificity (case-sensitive byte match)
| Commit message | Result |
|---|---|
| HERMES.md | ❌ 400 |
| hermes.md | ✅ OK |
| Hermes.md | ✅ OK |
| HERMES (no .md) | ✅ OK |
| HERMES.txt | ✅ OK |
| HERMES md (no dot) | ✅ OK |
| 6 HARD GUARDS (other capitalized phrase from same commit) | ✅ OK |
The filter matches the literal byte sequence HERMES.md only — no case normalization.
What's not a trigger
| Scenario | Result |
|---|---|
| File named HERMES.md in working tree (no git) | ✅ OK |
| File content containing HERMES.md (no git) | ✅ OK |
| Auto-loaded CLAUDE.md containing HERMES.md text (no git) | ✅ OK |
| Env var HERMES_WEBHOOK_URL | ✅ OK |
The trigger is specifically in the bytes Claude Code derives from git log and sends as system context.
Real-world reproduction
A repo with 50 commits where 12 messages referenced HERMES.md returned 400 every time. Diagnosis path:
- Shallow clone
--depth 1or--depth 2(fewer than 3 commits visible) → ✅ works --depth 3(commit607afc8 docs(...): HERMES.md 13-point review...becomes visible) → ❌ failsgit filter-repo --message-callback ...replace(b"HERMES.md", b"hermes-doc.md")→ permanent fix
Why this matters
- The error message is wrong. Claims quota exhaustion when none exists, sending users to billing settings unnecessarily. Content-filter rejection misclassified as quota error.
- It silently blocks legitimate use. "Hermes" is a perfectly reasonable name (Greek mythology, classical themes, internal service names) and
.mdis standard for markdown docs. - No actionable feedback. Users have no way to know the rejection is content-driven; the diagnostic path I followed (move CLAUDE.md → move .claude/ → remove project entry → bisect git history → bisect commit by commit → bisect message text → bisect words) took several hours.
Suggested fixes
- Don't classify content-filter rejections as billing errors. Return a distinct error type (e.g.,
content_filter_rejected) so clients can surface accurate messages. - Reduce false-positive scope. Matching the literal byte sequence
HERMES.mdis too broad. Consider context-aware filtering, not bare substring match in free-form text. - Document any system-context content that could be rejected so users can debug.
Environment
- Claude Code: v2.1.119 (latest)
- Plan: Claude Max 5x (OAuth,
rateLimitTier=default_claude_max_5x) - Platform: Linux 6.8 (Ubuntu)
- Auth:
~/.claude/.credentials.json, noANTHROPIC_API_KEYset - Date observed: 2026-04-25
- Related issues: #45020, #45033, #45028, #45095, #45390 (general "out of extra usage" reports — this is the first to identify a specific deterministic content-filter trigger)
---
Original real-world commit message that surfaced this bug
For full transparency / so engineers can analyze the byte sequences in case there is additional sub-pattern matching beyond the minimal HERMES.md trigger I isolated, here is the exact unmodified commit message in the repo that originally triggered the 400. Submitting verbatim because filter rules sometimes match on combinations / surrounding characters / unicode (em-dashes etc.) that minimal repros may not capture:
docs(session-118): HERMES.md 13-point review — profile model fix, schema, 6 HARD GUARDS, v0.11.0 notes
The 4 other commits in the same repo that also had HERMES.md in the message:
docs(session-118): update HERMES.md version to v0.11.0
docs: HERMES.md — Session 97c-fix5 Reviewer1 fallback + EP9 deprecation troubleshooting
- HERMES.md: Section 6 5-Layer Framework + ownOrderPlanId subsection + BANNED hindsight
HERMES.md updates:
- NEW HERMES.md (915 lines, 14 sections) — comprehensive Hermes Agent dev doc
Any of these in git log (depth ≥ that commit) → 400. Bisecting reduced the trigger down to HERMES.md alone, but the real-world messages contained additional content (em-dashes, parentheses, (session-NNN) prefix, all-caps phrases like BANNED, HARD GUARDS, version strings, etc.) that may share weight in whatever classifier is rejecting these.
3 Comments
Self-service diagnostic script for other affected users
I wrote a bash script that auto-bisects this 400 trigger in any git repo. If you hit "out of extra usage" on Max OAuth and suspect this content-filter bug, run it to find your own trigger string instead of bisecting commits manually for hours.
Gist: https://gist.github.com/DUMPDUMPY/e02a20e7c3503fbb884560b7def903e2
Usage
What it does (3 phases, ~5–10 min)
ANTHROPIC_API_KEYenv, version, OAuth state).git clone --depth Nto find the smallest depth that fails. Outputs the boundary commit SHA + message.Output: a Markdown report you can paste into a comment here so Anthropic engineers get more samples of the filter rule.
Sample run (a second repo of mine that also hit this)
Confirmed reproducible across two of my repos. Same root cause:
HERMES.mdsubstring in any commit message reachable from HEAD.What to do with the result
echo $(git rev-parse HEAD~$((LOW-1))) > .git/shallow && git reflog expire --expire=now --all && git gc --prune=now— shallows your local clone so the offending commit message isn't visible to git log.git filter-repo --message-callback 'return message.replace(b"<TRIGGER>", b"<replacement>")'(then force-push if you control the remote).Hope this helps anyone else stuck on the same false positive. If your bisection isolates a different trigger string, please paste it here — would be valuable evidence of the filter's broader scope.
Hi this should be fixed and we're reaching out to affected users and giving them a refund + another month of credits (in this case another $200). You should get an email soon if you were affected.
This issue has been automatically locked since it was closed and has not had any activity for 7 days. If you're experiencing a similar issue, please file a new issue and reference this one if it's relevant.