CLAUDE_CODE_NONBLOCKING_STDOUTでターミナル出力の凍結を防ぐ
一時停止したtmuxやSSH接続でセッションが固まる問題を、非ブロッキングstdout書き込みで回避する環境変数の使い方をまとめます。
このTipsでできること
CLAUDE_CODE_NONBLOCKING_STDOUTとは、ターミナル出力を非ブロッキングな経路で書き込むことで、出力側の詰まりによるセッションの凍結を防ぐClaude Codeの環境変数です。1に設定すると、ターミナル出力を2つ目の(追加の)非ブロッキングなファイルディスクリプタ経由で書き込むようになります。一時停止したtmuxのコントロールモードや、応答が止まったSSH接続のようにターミナル側が出力を読み取らなくなった場合でも、Claude Codeのセッションが途中で固まらなくなります。macOS・Linux・WSLでstdoutが端末に接続されているときに働き、Claude Code v2.1.261以降で利用できます。
やり方
シェルで一度設定するか、settings.jsonのenvキーに恒久的に書いておきます。
export CLAUDE_CODE_NONBLOCKING_STDOUT=1
claude毎回のセッションで有効にしたい場合は、~/.bashrcや~/.zshrcにこのexport行を追記します。設定が反映されているかは、同じシェルで値を確認してから起動すると確実です。シェルの環境変数はClaude Code起動時に読み込まれるため、値を変えても次にclaudeを起動し直すまでは反映されません。すでに起動している既存のセッションには影響しない点に注意してください。
echo $CLAUDE_CODE_NONBLOCKING_STDOUTチームやプロジェクト単位で常時有効にしたいときは、~/.claude/settings.json(自分だけ、全プロジェクト共通)または.claude/settings.json(プロジェクト共有、リポジトリにコミット)のenvキーに追記します。
{
"env": {
"CLAUDE_CODE_NONBLOCKING_STDOUT": "1"
}
}シェルとsettings.jsonの両方で設定した場合は、settings.json側の値が優先されます。Claude Codeはenvブロックの各エントリをプロセス環境に書き込み、シェルから継承した値を上書きするためです。
設定ファイルはどこに書くかで適用範囲が変わります。個人のリモート作業環境全般で有効にしたいなら~/.claude/settings.json、チーム全体でtmux/SSH運用を前提にしているプロジェクトなら.claude/settings.json(リポジトリにコミットして共有)が候補になります。
| ファイル | 適用範囲 |
|---|---|
~/.claude/settings.json | 適用範囲自分だけ、全プロジェクト共通 |
.claude/settings.json | 適用範囲プロジェクトの全員、リポジトリにコミット |
.claude/settings.local.json | 適用範囲自分だけ、このプロジェクトのみ(gitignore対象) |
| マネージド設定 | 適用範囲組織の全員、管理者が配布 |
複数の設定ファイルで同じ変数に別々の値を書いた場合は、マネージド設定が個人設定やプロジェクト設定より優先されます。個人用の~/.claude/settings.jsonで有効にしていても、組織のマネージド設定で明示的に無効化されていれば、その組織に属するすべてのプロセスでは無効のまま動きます。運用者側でtmux/SSH経由の作業を前提にした構成を配布したい場合は、マネージド設定に書いておくと個々人の設定を待たずに全員へ行き渡ります。
どんな症状に効くか
環境変数の説明文が挙げているのは、次の2つの典型的な状況です。
| 状況 | 何が起きるか |
|---|---|
| tmuxのコントロールモード(iTerm2連携など)が一時停止した | 何が起きるかターミナルが出力を読まなくなり、通常のブロッキング書き込みでは書き込み先の待ちでプロセスが止まる |
| SSH接続が応答しなくなった(ネットワーク切断・スリープ復帰待ちなど) | 何が起きるか同様に出力先が詰まり、リモートで動かしているClaude Codeのセッションがそのまま固まる |
どちらも「ターミナル側が出力を受け取れない状態になっている」点が共通しています。
なぜ通常の書き込みは固まるのか
一般に、プログラムがターミナルへ出力するとき、標準出力(stdout)への書き込みは同期的に行われます。書き込み先のバッファが埋まり、受け取る側(ターミナルエミュレータやSSHの先のプロセス)が読み出しを止めていると、書き込み処理自体がそこで止まり、後続の処理が進まなくなります。tmuxのコントロールモードを一時停止する、SSH接続が固まって応答しなくなる、といった操作は「受け取る側が読み出しを止める」状態そのものなので、この一般的な仕組みの上でセッション全体が動かなくなって見えることになります。CLAUDE_CODE_NONBLOCKING_STDOUTは、通常の書き込み経路とは別の非ブロッキングなファイルディスクリプタを通して書き込むことで、受け取る側の詰まりがメインの処理をブロックしないようにする設定です。
settings.jsonに書いたときの反映タイミング
環境変数をsettings.jsonのenvキーに書いた場合、多くの変数は保存した時点で実行中のセッションにも反映されますが、起動時に一度だけ読み込む系の変数は次回の起動まで反映されません(OpenTelemetry関連の設定がその例です)。CLAUDE_CODE_NONBLOCKING_STDOUTがどちら側に当たるかはドキュメントに明記がないため、確実に反映させたい場合は設定を書いたあとにセッションを再起動しておくのが無難です。
過去にも複数の「固まる」系修正がある
Claude Codeでセッションが動かなくなる不具合は、原因ごとに個別に修正されてきた経緯があります。
| バージョン | 修正内容 | 対象方向 |
|---|---|---|
| v2.1.15 | 修正内容MCPのstdioサーバーがタイムアウト時に子プロセスを終了させないまま固まる問題を修正 | 対象方向MCPサーバーとの通信 |
| v2.1.71 | 修正内容長時間セッションでキー入力が処理されなくなる「stdinの固まり」を修正 | 対象方向入力(stdin) |
| v2.1.73 | 修正内容複雑なbashコマンドの権限プロンプトで起きるフリーズと100%CPUループを修正。大量のskillファイル変更時のデッドロックも同時に修正 | 対象方向権限プロンプト・skill読み込み |
| v2.1.261 | 修正内容CLAUDE_CODE_NONBLOCKING_STDOUTを追加し、出力(stdout)側の固まりをオプトインで回避可能に | 対象方向出力(stdout) |
この並びは、入力側(stdin)や内部処理(権限プロンプト・skill読み込み)の固まりへの対応が先に進み、その後stdout側に手が入ったことを示しています。原因ごとに個別の修正やオプトイン設定が積み重なっている領域で、症状が似ていても直る箇所は都度違います。
原因の切り分け方
セッションが固まったとき、CLAUDE_CODE_NONBLOCKING_STDOUTが効く症状かどうかは次の観点で見分けます。
- キー入力が反応しない(stdin側)なら、この環境変数は対象外です。v2.1.71以降であれば既に修正済みの不具合の可能性があります
- 画面の更新が止まりCPUが高止まりする(権限プロンプトやskill読み込み絡み)場合も対象外です。v2.1.73以降なら修正済みの経路です
- tmuxのコントロールモードを一時停止した直後、またはSSH接続が応答しなくなった直後に固まる場合が、
CLAUDE_CODE_NONBLOCKING_STDOUTの対象です。原因は出力(stdout)側のブロックなので、ターミナル側の状態変化と固まるタイミングが一致するかを確認します
設定する前にclaude --versionでv2.1.261以降であることを確認してください。それより前のバージョンでは環境変数自体が存在せず、設定しても効果はありません。
補足
似た名前のMCP_CONNECTION_NONBLOCKINGは別の変数です。こちらはMCPサーバーへの接続をバックグラウンドで待つかどうかを制御するもので、ターミナル出力の固まりとは関係ありません。名前が近いため設定時に取り違えないよう注意してください。
この環境変数はstdoutが実際に端末に接続されているときにだけ効きます。パイプやリダイレクトで別プロセスに渡している場合、あるいは-p(非対話モード)でファイルや別コマンドに出力を流している場合は対象外です。対応OSもmacOS・Linux・WSL限定で、ネイティブWindows環境には適用されません。ネイティブWindowsでstdoutが取得できない別の不具合については、Claude CodeがWindowsでstdoutを取得できない原因と対処法で扱っています。原因も対象OSも異なるため、症状が似ていても混同しないよう注意してください。
設定を有効にしても効果を体感できるのは、実際にtmuxの一時停止やSSHの応答停止が起きたときだけのようです。「固まったことがある/リモート経由で長時間セッションを回す」利用形態でこそ効く設定です。
特に効きやすいのは、リモートの開発コンテナやクラウドVMにSSHでつないでClaude Codeを長時間走らせる運用、tmuxでセッションを多重化してバックグラウンドタスクを監視しながら作業する運用、ノートPCがスリープに入ってSSH接続が一時的に切れる環境です。いずれも「ターミナル側の受け取りが止まる瞬間」が日常的に起きやすく、放置していると気づかないうちにセッションが止まったままになりがちです。逆に、ローカルのターミナルを開いたままフォアグラウンドで使い続けるだけの環境では、この経路自体が発生しにくいため恩恵は限定的です。
CLAUDE_CODE_NONBLOCKING_STDOUTは1を設定すると有効になります。Claude Codeのドキュメントは、オン/オフを切り替えるタイプの環境変数について「1またはtrueで有効、0またはfalseで無効(大文字小文字は区別しない)」という共通の受理形式を定めており、値の有無だけを見る一部の変数(DISABLE_TELEMETRY等)だけがこの例外として個別に挙げられています。CLAUDE_CODE_NONBLOCKING_STDOUTはその例外リストに含まれていないため、trueや0・falseで指定しても同じ規則に従い、TRUEのような大文字表記でも問題なく解釈されます。
設定しても解決しない場合
CLAUDE_CODE_NONBLOCKING_STDOUT=1を設定しても同じ症状が続く場合、原因が別にある可能性があります。ログ出力先を切り替えて詳細を確認するには、--debugと--debug-fileでログ出力先を切り替える方法が使えます。固まった瞬間の内部ログを別ファイルに残しておけば、tmuxやSSH側の状態変化と実際のタイムスタンプを突き合わせて切り分けやすくなります。
よくある質問
常時有効にしておいてデメリットはあるか
ドキュメントには副作用に関する記載はありません。対象がmacOS・Linux・WSLでstdoutが端末に接続されている場合に限られる設定なので、該当しない環境やモードでは単に効果がないだけです。恒久的にsettings.jsonへ入れておいても支障はないと考えられます。
同じ設定手順で使える他の環境変数
Claude CodeにはCLAUDE_CODE_NONBLOCKING_STDOUTのように、特定の状況でだけ効く環境変数がほかにもあります。複数セッションでタスクリストを共有するCLAUDE_CODE_TASK_LIST_IDもその一つです。用途が違う変数でも、設定手順(シェルのexportかsettings.jsonのenvキー)は共通です。
まとめ
CLAUDE_CODE_NONBLOCKING_STDOUT=1を設定すると、一時停止したtmuxコントロールモードや応答が止まったSSH接続が原因でClaude Codeのセッションが固まる状況を避けられます。効果があるのはmacOS・Linux・WSLでstdoutが端末に接続されている場合のみで、対応にはv2.1.261以降が必要です。リモート経由の長時間セッションや、tmux連携で作業することが多い環境では、~/.claude/settings.jsonに恒久設定として入れておくと安心です。
設定してもなお固まる場合は、まずclaude --versionでバージョンを確認し、次に症状がstdin側や権限プロンプト側の別原因ではないかを切り分けてから、--debug-fileでログを残して調べる、という順に進めると原因にたどり着きやすくなります。