The Claude Code Changelog
All Episodes
Stop CI Jobs From Waiting Hours on Claude Usage Limits

Stop CI Jobs From Waiting Hours on Claude Usage Limits

0:00|0:00

Claude Code 2.1.301 adds CLAUDE_CODE_RETRY_WATCHDOG_MAX_USAGE_LIMIT_WAIT_MS, letting CI jobs fail quickly or switch to a fallback model instead of idling through a distant quota reset. Learn how to set it alongside the general retry wait cap, where to scope the watchdog variables, and what “per API request turn” means. Also covered: richer OpenTelemetry tool-decision events, safer worktree cleanup, clearer Grep and Glob errors, and several usability fixes.


Chapter 1

Stop Paying for Four Hour Usage Limit Waits in CI

Lachlan Reed

Picture a CI runner at two in the morning, politely waiting for a usage limit that won't reset for four hours, while the billing meter keeps ticking. That's the failure mode Claude Code 2.1.301 goes after. It shipped October 15, 2026. This is The Claude Code Changelog, brought to you by Jellypod AI. I'm Lachlan.

James Turner

And I'm James. Last time we covered CLAUDE_CODE_RETRY_WATCHDOG_MAX_WAIT_MS, which stops unattended runs from hanging forever on 529 overload errors. This release adds the sibling variable: CLAUDE_CODE_RETRY_WATCHDOG_MAX_USAGE_LIMIT_WAIT_MS. Here's the change. In unattended retry mode, the one you turn on with CLAUDE_CODE_RETRY_WATCHDOG, Claude Code now looks at how far away a usage limit reset is. If the reset is further out than your threshold, it ends the request instead of sitting there waiting.

Lachlan Reed

Why that matters comes down to two kinds of failure that used to be treated alike. A 529, or a burst rate limit, clears in seconds or a couple of minutes. Waiting is the right call there. But a hard usage limit, like an organization token ceiling, a daily quota, or a rolling tier window, can have a reset hours away. If you'd set the general wait cap to fifteen or thirty minutes, a runner hitting a four hour limit would burn the whole cap idling before it gave up. And if you hadn't set a cap, it hung until your CI platform killed it, usually with a log that told you nothing useful.

James Turner

Right, so the two variables split the jobs. One says how long you'll tolerate transient trouble. The other says how long you'll tolerate a quota reset. Here's a pattern for a pipeline step. Export CLAUDE_CODE_RETRY_WATCHDOG equals 1. Then set CLAUDE_CODE_RETRY_WATCHDOG_MAX_WAIT_MS to 600000, so ten minutes for overloads. Then set CLAUDE_CODE_RETRY_WATCHDOG_MAX_USAGE_LIMIT_WAIT_MS to 0, so any usage limit that isn't already clear fails right away. Then run your headless job, say claude in print mode with npm test, and add the fallback model flag pointing at Haiku 5.5.

Lachlan Reed

And that fallback bit is the clever part. When the primary model hits a usage limit and the watchdog aborts immediately, Claude Code can drop to the fallback model right away instead of freezing the job. You're swapping a four hour stall for a quick downgrade, or at worst a clean, fast failure you can see in the logs. If zero feels too strict, put in something like sixty seconds. Pick it based on what a wait is actually worth to you.

James Turner

A few caveats. First, scope. Like the general wait cap, this threshold applies per API request turn, not across the whole multi turn pipeline. So a long job is judged one request at a time. Second, and this one's important: don't export these watchdog flags in your interactive shell profile. Not in your zshrc, not in your bashrc. In an interactive session, a rate limit would just look like Claude froze. Keep them scoped to the CI job or the script.

Lachlan Reed

Now, a few smaller things in 2.1.301 worth knowing. For teams on OpenTelemetry, tool_decision events now carry classifier_verdict and permission_mode, so you can tell an auto mode classifier decision apart from a plain permission rule. Set OTEL_LOG_TOOL_DETAILS to 1 and you also get classifier_category, which names the built in rule a classifier block matched.

James Turner

Two fixes I like. Quitting no longer removes a worktree created by a WorktreeCreate hook without asking when it might hold unpushed commits. That's a real data loss guard. And Grep and Glob used to report no matches when the search program failed unexpectedly. Now they return an error saying the search failed, so the agent doesn't conclude that code doesn't exist when the search simply broke.

Lachlan Reed

Plus the Read tool no longer reads binary files like xlsm, parquet, epub and heic as text. And if you switch to a model with a smaller context window, the previous model now summarizes the conversation first, and it no longer spends usage credits on that summary without asking.

James Turner

And vim mode users get the percent motion, which jumps to the matching bracket, alone or with d, c, or y. Also, Escape no longer discards a typed answer to an AskUserQuestion prompt. The free text field now supports NORMAL mode, and Escape only cancels from NORMAL. That's 2.1.301. Go check your CI env block.