Claude CodeがNixOSでCPUとメモリを食う原因と0444での回避策
NixOSやhome-managerで設定をsymlink管理すると、アイドルのClaude Codeが/nix/storeを走査してCPUとメモリを使い切る報告があります。症状の見分け方と回避策です。
NixOSでnix buildを回すたびに、何もしていないはずのClaude CodeがCPUを使い切り、数GBのメモリまで抱え込む。anthropics/claude-codeのissue #98701は、この症状を設定ファイルの監視が原因だと報告しています。
issueは2026-10-01に立てられ、まだクローズされていません。回避策は報告者の間で確認されていて、environment.etcのmodeを"0444"にして設定をsymlinkでなくコピーにします。
症状: アイドルなのにCPUが張り付く
#98701の報告者はLinux(NixOS)でv2.1.280とv2.1.283を使い、ターミナルマルチプレクサ配下で複数のセッションを動かしていました。見えた症状は次のとおりです。
- アイドルのセッションをstraceすると、
/nix/store/*へのstatxが毎秒約18,000回 - 1セッションあたりCPU 40〜150%で、全セッションが同じタイミングで動く
- 数時間でRSSが4〜7GBに膨らむ(ヒープダンプは文字列4,500万個、Promise 230万個)
- 約12セッションで62GBのRAMとスワップを使い切り、OOM killerがデスクトップセッションを落とした
コメントでは別の利用者が、64GBのマシンで約17セッションを動かし、2日続けてメモリとCPUが尽きたと書いています。セッションは約20分で1GBから5GBに増え、それぞれ230〜370%のCPUを使いました。ピークは他のセッションのnix buildと重なっていたそうです。
見分けるときの手がかり
- 負荷が出るのは、同じマシンで
nix buildやnixos-rebuildなどストアが書き換わった直後 - 全セッションが同時に重くなる(セッションごとの暴走ではない)
/etc/claude-code/managed-settings.jsonや~/.claude/settings.jsonがストアへのsymlink
原因: symlinkの行き先の親ディレクトリを監視している
Claude Codeは設定ファイルを監視し、変更があれば実行中のセッションに反映します。managed settingsのファイルも同じで、Linuxでは/etc/claude-code/managed-settings.jsonが対象です。分割して置くmanaged-settings.d/の*.jsonも読まれます。
NixOSのenvironment.etcは、既定でファイルを/nix/store/<hash>-etc-...へのsymlinkとして/etcに置きます。#98701の報告では、設定ウォッチャーがこのsymlinkを解決し、行き先の親ディレクトリを監視していました。つまり、/nix/storeそのものにinotifyの監視が付きます。
ストア直下に変化があると、全セッションが同時にディレクトリを読み直します。#98701の環境ではエントリ数が約21万でした。この全走査の繰り返しがCPUの張り付きと、文字列とPromiseの大量生成によるヒープ増の元だと、報告者は見ています。
別の利用者は、回っていたセッションがビルドの停止後に約600MBまで自然に戻ったと書いています。恒久的なリークというより、走査が続く間だけ膨らむ挙動のようです。
#86935では、Anthropic側とみられるコメントが原因に触れています。symlinkのときは行き先の親ディレクトリを監視する仕様で、2.1.139でアトミックな保存(rename)を拾うために入ったものです。そのディレクトリ監視はイベントのたびに全エントリをstatし、ディレクトリの大きさに上限がありません。2.1.233のmacOSで再現が確認され、通常ファイルなら約0.3%のCPUが、symlinkだと100〜200%になったとのことです。
home-managerやmacOSでも同じ型
symlinkの行き先がストアにある構成なら、managed settingsに限らず同じ形になります。
| 報告 | 環境 | symlinkの対象 | 現れた症状 |
|---|---|---|---|
| #98701 | 環境NixOS | symlinkの対象/etc/claude-code配下のmanaged settings | 現れた症状約21万エントリのストアを全セッションが走査、数GBのヒープ |
| #98701のコメント | 環境NixOS(btrfs) | symlinkの対象home-managerの~/.claude/settings.json | 現れた症状47プロセス中46が/nix/storeを監視、ロードアベレージ500〜800 |
| #86935 | 環境macOS | symlinkの対象home-managerの~/.claude/settings.json | 現れた症状約37万エントリのストアを走査、アイドルで300〜500%のCPU |
#86935はv2.1.224のmacOSでの報告で、nix buildの最中にアイドルのセッションがlstatとgetdirentries64を繰り返し、ビルドの側が遅くなったと書いています。45秒の観測で、ストア全体の走査は約2回でした。通常のファイルに置き換えると、ストアへのシステムコールが20秒あたり215,483回から0に落ちたとのことです。
NixOSのコメントでは、約95,000エントリのbtrfsストアで約740スレッドがD状態になり、32コアのマシンが数分間応答しなくなった例もあります。
自分の環境が当てはまるか確かめる
まず、設定ファイルがストアを指しているかを見ます。
readlink -f /etc/claude-code/managed-settings.json
readlink -f ~/.claude/settings.jsonどちらかが/nix/store/で始まれば、条件に合います。次に、実行中のセッションがストアのinotify監視を持っているかを調べます。報告者は/proc/<pid>/fdinfoで確かめています。
ino=$(printf '%x' "$(stat -c %i /nix/store)")
for p in $(pgrep -x claude); do
grep -l "inotify.*ino:$ino " /proc/$p/fdinfo/* 2>/dev/null \
&& echo "pid $p が /nix/store を監視"
donefdinfoのinotify行は、監視対象のinodeを16進で示します。上のコマンドはそれと/nix/storeのinodeを照合する書き方の一例です。プロセス名がclaudeと一致しない環境(ラッパー経由など)では、pgrep -fに変えて調整してください。
回避策: symlinkをやめて、通常のファイルにする
報告で共通しているのは、行き先の親ディレクトリがストアにならないようにする方法です。
environment.etcの場合: mode = "0444"
#98701の報告者とコメントの利用者は、environment.etc.<file>.modeを"0444"にして解消しています。NixOSはmodeを指定すると、symlinkではなくファイルをコピーして置くためです。
environment.etc."claude-code/managed-settings.json" = {
text = builtins.toJSON {
# 管理したい設定をここに書く
};
mode = "0444";
};上は、報告された回避策を書き下した例です。切り替えてセッションを再起動すると、同じストア変更でCPUが0%、書き込みが約1回/秒になったと報告されています。symlinkを残したセッションは約22%のCPUと毎秒約28,000回の書き込みでした。
コメントの利用者は、切り替え後の新しいセッションが/etc/claude-codeだけを監視し、ストアは監視しないことをfdinfoで確認しています。その利用者の環境では、--settingsでストア内のファイルを指定しても問題は出ず、引き金になったのはmanaged settingsのsymlinkだけでした。
home-managerの場合: 通常ファイルとして置く
home-managerの設定ファイルにはmodeのような項目がないと、コメントの利用者は書いています。その利用者は~/.claude/settings.jsonを通常のファイルにして、監視対象の親を~/.claudeにする方法を取り、home-manager側ではコピーする処理をactivationに組み込む必要があると述べています。
注意点が1つあります。設定の保存はテンポラリファイルを書いてrenameする方式で、symlinkを1段しか解決しないという別の報告(#78162)があります。symlinkの先が読み取り専用だと保存に失敗するので、コピーで通常ファイルにする方針はこの点でも筋が通ります。消える側の症状はhome-managerのsymlink運用でsettings.jsonが消える件で整理しています。
修正の状況
報告者は修正案として、次の2つを挙げています。
- symlinkの行き先ではなく、設定ファイルのパスを含むディレクトリ(
/etc/claude-codeや~/.claude)を監視する /nix/storeのように読み取り専用で不変の場所は監視しない
#86935は監視をファイルそのものにする案のほか、エントリ数が多いディレクトリでは走査せず単一ファイルをstatで見る案と、走査中の再入を避けるデバウンスも挙げています。
v2.1.302でも再現が報告されており、どちらのissueもopenです。changelogには、この症状の修正を告げる項目がありません。直ったかどうかは、使っているバージョンで上の確認コマンドを回し、/nix/storeの監視が消えているかで判断できます。
切り替えたあとに確かめること
設定を切り替えても、すでに動いているセッションは古い監視を持ったままです。#98701の測定でも、再起動したセッションだけが0%になり、残したセッションは負荷が続いていました。切り替え後は全セッションを一度終了して起動し直します。
効いたかどうかは、先ほどのfdinfoの確認コマンドで見ます。/nix/storeを監視するプロセスが0件になり、nix store add-file <任意のファイル>のようなストアへの書き込みを起こしてもCPUが動かなければ、symlinkが原因だったと言えます。報告者の再現手順も、このnix store add-fileでした。
負荷が残る場合は、ストアを指す別のsymlinkが残っていないかを疑います。managed settingsをmanaged-settings.d/に複数ファイルで置いている構成は、ファイルごとにsymlinkになるので、すべてにmode = "0444"を付けます。#98701の報告者の環境も、managed-settings.jsonとmanaged-settings.d/*.jsonの両方がsymlinkでした。
切り分けの順番
CPUが張り付く症状はNix以外でも起こるので、次の順で絞ると早く済みます。
NixOSでClaude Codeが重いときの切り分け
- Q設定ファイルは`/nix/store`へのsymlinkですか?答えがこの原因ではない可能性が高い答えがはい
次へ進みます。
- Q`nix build`などの直後に、複数のセッションが同時に重くなりますか?答えがセッション単独の問題として別の原因を探します答えがはい
fdinfoの確認コマンドで、
/nix/storeの監視を持つプロセスを探します。
symlinkをコピーに変える
environment.etcならmode = "0444"、home-managerなら通常ファイルとして置き、セッションを再起動します。
NixOSでのClaude Codeには、ほかにサンドボックスまわりの症状もあります。bwrapが失敗する場合はNixOSでbwrapエラーになる原因、権限エラーになる場合はサンドボックスがNixOSで権限エラーになる件を参照してください。
まとめ
CPUとメモリの暴走は、設定の中身ではなく、設定ファイルがストアへのsymlinkであることから来ます。environment.etcのmode = "0444"でコピーにすれば、報告者の環境ではストアの監視が消えました。ストアの規模が大きいほど、同時に動かすセッション数が多いほど、効き方が大きくなります。
参照した一次ソース
この記事の記述は、次の一次ソースと照合しています。更新時に参照先が変わった場合は一覧も更新します。