沒人看著的 Claude Code,別去調重試次數:RETRY_WATCHDOG、MAX_RETRIES 與兩個 timeout 怎麼選
一個 API 請求在串流時一直失敗,Claude Code 把它重送了 21 次。
這是 CHANGELOG 2.1.285 修掉的 bug,原文寫的是「a failing API request being retried up to 21 times when streaming kept failing」。官方文件講的預設明明是重試 10 次,多出來的那一截,來自串流失敗之後改走的非串流備援:它沒有跟原本的請求共用額度,自己又拿到一整份新的重試次數。修法是讓備援改用同一份預算。下一版 2.1.286(也是我寫這篇時 CHANGELOG 上最新的一版)再往前一步,把計數單位改成「一整次模型呼叫」,照預設設定,一次失敗的呼叫最多送出 14 個請求。
bug 已經修掉了,讓我在意的是:重試次數這個數字,連官方自己都在最近連續兩版裡重新數過。你在自己的 CI 裡想「保險一點,把重試調大」,調的其實是一個你看不太到全貌的東西。
所以這篇要回答的問題很窄。Claude Code 打 API 失敗的時候,你手上有四顆旋鈕:CLAUDE_CODE_MAX_RETRIES、CLAUDE_CODE_RETRY_WATCHDOG、API_TIMEOUT_MS、CLAUDE_STREAM_FIRST_BYTE_TIMEOUT_MS。什麼情況該轉哪一顆?
先交代一下:這篇只讀了官方的 errors 頁、環境變數表、headless 頁 與 CHANGELOG,沒有實際跑過任何一個設定,也沒量過重試實際要等多久。下面的預設值與上限都照文件原文,至於重試在真實環境裡會耗掉多少時間,我沒有數據可以給你。
送貨員按門鈴
快遞送到你家,按門鈴沒人應。正常的送貨員會隔一陣子再按,等的間隔越拉越長,按到第十次還是沒人,就貼張招領單走人。
這就是 Claude Code 的預設行為。文件原文是「retries transient failures up to 10 times with exponential backoff before showing you an error」,伺服器錯誤、overloaded、逾時、斷線、暫時性的 429 節流,都在這個範圍。你在畫面上看到錯誤訊息的時候,它已經把該做的重試做完了。重試期間 spinner 會顯示 Retrying in Ns · attempt x/y 的倒數,人在終端機前面的話,看得到它在努力。
有一種失敗它刻意不重試:回應已經送到一半,Claude 已經完成了一段文字或一個工具呼叫,這時候才斷線或吃到伺服器錯誤。文件給的理由很直接,重跑「could execute the same tool calls twice」。送貨員已經把一半的貨搬進你家客廳,他不會再從頭搬一次,因為那會讓你收到兩份。Claude Code 會保留已完成的部分,顯示 The response above may be incomplete 這類訊息,從已完成的工具結果接著往下走。
所以有一整類失敗,重試次數調多高都沒用,它根本不在重試的路徑上。
沒人在家的那一天
現在換個情境。CI job、eval harness、跑在遠端的 worker,三更半夜沒有人盯。服務剛好在那段時間過載,回了一串 529。
直覺的做法是把 CLAUDE_CODE_MAX_RETRIES 調大,叫送貨員多按幾次。這條路官方已經替你堵掉了:2.1.186 的 CHANGELOG 寫「Changed CLAUDE_CODE_MAX_RETRIES to cap at 15; for unattended sessions, use CLAUDE_CODE_RETRY_WATCHDOG instead」。上限壓在 15,同一句話裡就把你指去另一顆旋鈕。環境變數表對 CLAUDE_CODE_MAX_RETRIES 的說明也是同一個意思,最後一句是「For unattended sessions that need to wait through longer outages, set CLAUDE_CODE_RETRY_WATCHDOG instead」。
兩顆旋鈕看起來像同一類東西,管的卻是不同的事。MAX_RETRIES 回答「按幾次門鈴」。RETRY_WATCHDOG 回答的是另一個問題:要不要乾脆在門口等到你回家。
設成 1 之後,429 和 529 這兩種容量類錯誤會無限重試,不再按 CLAUDE_CODE_MAX_RETRIES 的次數放棄。重試之間最多退避 5 分鐘;如果回應裡帶了限額重置時間,就等到重置為止,所以碰到使用量上限的 session 會把剩下的時段等完。從 v2.1.199 起,它另外把伺服器錯誤、逾時、斷線這些非容量類暫時性錯誤的預設重試次數拉到 300,文件說大約是三小時的退避,同時拿掉你自己明確設定 CLAUDE_CODE_MAX_RETRIES 時的 15 次上限。
設法照官方環境變數頁的寫法,在 shell 裡先 export 再啟動:
1 | export CLAUDE_CODE_RETRY_WATCHDOG="1" |
或寫進 settings.json 的 env 區塊,這樣不管 claude 是怎麼被叫起來的都會生效:
1 | { |
兩段的格式是照抄官方範例的,官方範例裡放的是 API_TIMEOUT_MS,我把變數名和值換成 watchdog 的。
帳單寄到的時候,它不等了
watchdog 的「無限等」只對容量類錯誤成立。環境變數表在同一格裡寫著:「Claude Code fails at once when a standard-speed request gets a 429 that reports a spend limit or exhausted usage credits, even one from a gateway spend cap that resets on a schedule.」標準速度的請求只要吃到回報花費上限或額度用完的 429,就算那是 gateway 定期會重置的花費上限,它也立刻失敗。
回到送貨員。對方不在家,他可以在門口等;可是這是一件貨到付款的包裹,而你的帳戶被凍結了,他等到天亮也收不到錢,所以直接退件。
這條規則是後來才加的。文件同一段寫「Before v2.1.239, the watchdog retried these indefinitely」,2.1.239 的 CHANGELOG 也寫 watchdog 改成碰到組織花費上限與額度用完時「fails immediately」,不再無限期等重置。換句話說,舊版碰到帳單類的 429 會一直等到重置;現在連 gateway 那種會定期重置的花費上限,它都不等了。為什麼這樣改,CHANGELOG 只寫了改成什麼,沒寫理由。
注意兩種「上限」在文件裡的待遇不同。帶有限額重置時間的使用量上限,watchdog 會等到時段重開;回報花費上限或額度用完的 429,它立刻失敗。如果你的無人值守 job 最常死在帳單上,開 watchdog 救不了你,該補的是花費上限的監控與調整。另外,2.1.281 才修掉「watchdog 在一連串 429/529 等待之後,碰到第一個 5xx 或斷線就失敗」的問題,版本比這舊的話,別太相信它撐得住。
上面那句講的是標準速度的請求。fast mode 的請求,環境變數表直接把你指到另一頁 fast mode 的限額處理,那頁的說法是遇到限額會自動退回標準速度。有開 fast mode 的話,要另外讀那一頁。
所以無人值守那一格,我的判準是:失敗大多來自過載或暫時性網路問題,開 watchdog;失敗大多來自花費上限,watchdog 幫不上忙。還有一件事是我自己的判斷,文件沒寫:一個可能退避三小時的 session,外層的 CI job 最好有自己的逾時。不然「它還在耐心重試」和「它卡死了」,從外面看是同一個畫面。
腳本裡,你要的是它早點放棄
第三種情境剛好反過來。你在寫一支腳本,外層已經有自己的重跑邏輯,或者有排好的下一輪會接手。這時候讓 Claude Code 在裡面按十次門鈴、每次越等越久,只是把「出事了」這個訊號往後拖。
errors 頁對 CLAUDE_CODE_MAX_RETRIES 的註解就寫著這個用途:「Lower it to surface failures faster in scripts」。調低,讓失敗早一點浮出來,交給外層決定要不要再來一次。文件沒有建議一個具體的數字,我也不替它編一個;你外層的重跑間隔有多長,大概就決定了裡面值得等多久。
這裡有一個意外好用的東西。用 headless 模式跑的時候,Claude Code 重試之前會送出一個 system/api_retry 事件,裡面有 attempt(從 1 起算)、max_retries、retry_delay_ms、error_status(沒拿到 HTTP 回應時是 null)和 error 類別,像 rate_limit、overloaded、server_error。你的外層程式讀得到它正在第幾次、下一次要等幾毫秒、卡在哪一類錯誤,不用盯著 log 猜。
max_retries 這個欄位的說明值得多看一眼:「total retries permitted for this failure’s cause, which can be fewer than the session-wide budget」。它是這一類失敗允許的次數,可能比整個 session 的預算還少。開頭那個 21 次的 bug、2.1.286 改成以整次模型呼叫計算,再加上這一句,「重試幾次」就很難當成一個單純的全域數字來看:計數單位最近剛改過,不同原因的失敗分到的次數也可能不一樣。
說到計數,有一個數字我到現在還拼不起來:2.1.286 那個「最多 14 個請求」。預設重試 10 次,為什麼上限是 14,CHANGELOG 沒有說明。errors 頁提到串流停滯的那一次重送是算在 10 次預算之外的,但光靠這幾句能不能剛好湊出 14,我算不出來。如果你的 CI 剛好有 system/api_retry 的事件紀錄,數一數一次失敗的呼叫實際送了幾個請求,應該就是最快的答案。
慢,不等於失敗
最後一種情況最容易被誤診成重試問題。請求其實沒有失敗,只是你公司的 proxy 或 gateway 習慣把整個回應扣住,等全部完成才一次吐給你。這時候你會看到這種訊息:
1 | API Error: No response from API (waited 3m, then 10m on the retry). If a proxy or gateway on your network holds responses until they complete, raise API_TIMEOUT_MS or CLAUDE_STREAM_FIRST_BYTE_TIMEOUT_MS to wait longer. |
訊息自己就把解法寫出來了,而且它點名的兩顆旋鈕都跟重試次數無關。我的讀法是,這種情況卡住的是「等多久」,不是「重送幾次」,proxy 不放行,按幾次門鈴都一樣。
API_TIMEOUT_MS 是單一請求的逾時,預設 600000 毫秒,也就是 10 分鐘,上限 2147483647。超過上限有個陷阱,文件原文是「Values above the maximum overflow the underlying timer and cause requests to fail immediately」。你以為設了一個超大的值叫它等久一點,實際上是讓每個請求當場失敗。
CLAUDE_STREAM_FIRST_BYTE_TIMEOUT_MS 管的是串流請求的第一個位元組要在多久內到,需要 v2.1.242 以上,設定值會被夾在 10 秒到 30 分鐘之間。這兩個計時器跟 Claude Code 裡其他計時器(Bash、MCP 工具那些)怎麼分工,我在〈它不是壞掉,是被計時器砍掉:Claude Code 的 timeout 與輸出上限〉整理過,這裡就不重複。
另一條路是乾脆換一個模型繼續跑,那是〈Claude Code Fallback Models 完整教學〉講的 --fallback-model。重試是同一個送貨員再按一次門鈴,fallback 是換一個送貨員。
所以,轉哪一顆
先問有沒有人在看。人在終端機前面,什麼都不用設,預設的 10 次加上畫面上的倒數就夠了。沒人看,開 CLAUDE_CODE_RETRY_WATCHDOG=1,不要去碰 MAX_RETRIES 的上限。外層有自己的重跑邏輯,把 MAX_RETRIES 調低。錯誤訊息裡出現「No response from API」,問題在計時器,轉 timeout。
會讓我改掉第二條的只有一種情況:你的無人值守 job 失敗紀錄裡,大多數是花費上限或額度用完的 429。那 watchdog 一碰到就會立刻失敗,開不開差別不大,該處理的是帳單那一側。
原文來源:Error reference - Claude Code Docs、Environment variables - Claude Code Docs、Run Claude Code programmatically - Claude Code Docs、Claude Code CHANGELOG(皆為 10 月 1 日讀取的版本)


















