Claude Codeで「too many levels of symbolic links」——自己参照シンボリックリンクバグが3回再発した記録

Claude Codeで「too many levels of symbolic links」——自己参照シンボリックリンクバグが3回再発した記録

claudeコマンドが「too many levels of symbolic links」で動かなくなる不具合。原因はネイティブインストーラーが~/.local/bin/claudeを自己参照する相対シンボリックリンクに書き換えること。2026年4月から3回報告されながら未修正の経緯と応急処置・再発防止策を整理した。

エンジニアのゆとです。

Linuxのネイティブインストーラーでclaudeを使っていると、ある日突然こう言われて詰むことがある。

$ claude
zsh: too many levels of symbolic links: claude

ファイル自体はちゃんとある。~/.local/share/claude/versions/の下を見ると、該当バージョンのバイナリは実行可能な状態でそこに転がっている。壊れているのは~/.local/bin/claudeという、そのバイナリを指すはずのシンボリックリンク1本だけだ。

これ、実は2026年4月から3回、別々のGitHub Issueで報告されている再発バグで、今日(2026年9月)の時点でも直っていない。しかも3回とも「再現手順あり・原因の見立てあり」の状態で、Anthropicのstale bot(長期無応答Issueを自動クローズするボット)に閉じられて終わっている。今回はこの一部始終を、Issue番号付きで追ってみる。

まず結論——原因はインストーラーが書く相対シンボリックリンクの自己参照

先に結論だけ書く。

  • 症状: claudeコマンドがtoo many levels of symbolic links(bashだとToo many levels of symbolic links、環境によってELOOPとも表示される)で失敗する
  • 原因: ネイティブ(standalone)インストーラーが、バージョンを切り替えるタイミングで~/.local/bin/claudeを相対パスの自己参照シンボリックリンクに書き換えてしまう
  • 壊れたリンクの実体: ~/.local/bin/claude -> claude/versions/2.1.xxxという形の相対リンクが書き込まれる。これは~/.local/bin/claudeというシンボリックリンク自身から見た相対パスなので、展開すると~/.local/bin/claude/versions/2.1.xxxになり、先頭のclaudeがシンボリックリンク自身を指す——つまり自分の中に自分がいる無限ループになる
  • 発生対象: Linux + ネイティブ(standalone)インストーラー(installMethod: "native")。npm経由のグローバルインストールでは起きない
  • 状態: 2026年4月・5月・9月と3回報告されているが、記事執筆時点(Claude Code 2.1.273)でも根本修正は入っていない

まずは直し方から知りたい人向けに、応急処置を先に書く。

今すぐ直す——壊れたシンボリックリンクを手動で張り替える

too many levels of symbolic linksが出たら、まず今動いているバイナリの実体を確認する。

ls -la ~/.local/share/claude/versions/

ここに2.1.xxxのようなディレクトリ、またはそのままバイナリファイルが並んでいるはずだ。存在するバージョンの中で一番新しいものを確認したら、壊れたシンボリックリンクを消して、絶対パスで張り直す。

rm ~/.local/bin/claude
ln -s "$HOME/.local/share/claude/versions/2.1.xxx" ~/.local/bin/claude
claude --version

claude --versionが通れば復旧できている。ポイントはln -sの第一引数を絶対パスにすること。$HOMEを展開させずに~をそのまま書いたり、相対パスで書いたりすると、次のバージョン更新のタイミングで同じ壊れ方をする可能性が高い。

再インストールで直したい場合は、公式の入れ直し手順に沿う。

Claude Codeを完全にアンインストールする方法 — インストール方法の見分け方から設定ファイル削除、再インストールまで【2026年版】
Claude Codeを完全にアンインストールする方法 — インストール方法の見分け方から設定ファイル削除、再インストールまで【2026年版】Claude Codeのアンインストール手順を、ネイティブ/Homebrew/WinGet/apt/npmのインストール方法別に公式ドキュメントベースで整理。消したはずのclaudeコマンドが動き続ける原因、設定ファイル削除の注意点、クリーン再インストールが効くケースまで解説する。読む →

再インストール後にまた同じ症状が起きたら、次の章の原因を踏まえてXDG_DATA_HOME環境変数を確認してほしい。

なぜ「自己参照」になるのか——相対パスが牙を剥く仕組み

このバグの面白いところは、原因が単なる「パスの書き間違い」ではなく、相対パスの解決規則そのものにあるところだ。

シンボリックリンクは、相対パスで書かれた場合「リンクファイルが置かれているディレクトリ」を基準にパスを解決する。正常なケースでは、インストーラーは~/.local/bin/claudeに対して次のような絶対パスのリンクを書く。

~/.local/bin/claude -> /home/<user>/.local/share/claude/versions/2.1.xxx

これなら何の問題もない。ところがバグが発生すると、インストーラーは絶対パスの代わりにこう書いてしまう。

~/.local/bin/claude -> claude/versions/2.1.xxx

このclaude/versions/2.1.xxxは相対パスなので、「~/.local/bin/claudeが置かれているディレクトリ」、つまり~/.local/bin/を基準に解決される。展開すると~/.local/bin/claude/versions/2.1.xxxになるが、この最初のclaudeという要素こそが、まさに今読もうとしているシンボリックリンクファイルそのものだ。

つまりOSは「~/.local/bin/claudeを開け」と言われて、リンク先のclaude/versions/2.1.xxxを読みに行き、その中の最初のclaudeがまた同じシンボリックリンクを指しているので、また同じ場所に戻ってくる。これを無限に繰り返した結果、LinuxカーネルはELOOP(シンボリックリンクの再帰段数が多すぎる)としてエラーを返す。これがtoo many levels of symbolic linksの正体だ。

バイナリ本体(~/.local/share/claude/versions/2.1.xxx)は正しい場所に届いていて壊れてもいない。壊れているのは、そこへの入り口となるリンク1本だけ——というのがこのバグの厄介さで、「アンインストール→再インストール」を繰り返しても、次のバージョン切り替えのタイミングで同じ壊れ方が再発する理由になっている。

3回report、3回stale bot closed——半年間直っていない経緯

このバグはGitHub上で少なくとも3回、独立した番号のIssueとして報告されている。時系列で並べると以下のようになる。

Issue報告日対象バージョンクローズ日・理由
#452602026年4月8日2.1.96前後2026年5月22日、無応答による自動クローズ(未修正)
#628222026年5月27日2.1.1522026年5月31日、#45260の重複としてクローズ(未修正)
#747382026年7月6日2.1.2012026年9月15日、無応答による自動クローズ(未修正)

最初の#45260では、standaloneのauto-updaterが~/.local/share/claudeではなくカレントディレクトリ($CWD)にclaude/versions/を作ってしまい、そこに紐づく形で相対シンボリックリンクが壊れる、という報告だった。$HOMEからclaudeを起動したときだけ偶然動き、他のディレクトリから起動すると即座にELOOPになる、という再現条件まで書かれていたが、このIssueは「長期間反応がない」という理由でstale bot(自動クローズボット)に閉じられ、修正はされなかった。

3週間ほどで#62822として同じ不具合が再報告される。報告者は「#45260と同じ不具合で、まだ直っていない」と明記した上で、2.1.152での再現ログを添えて再提出している。このIssueは#45260の重複として処理され、やはり修正コミットには結びつかなかった。

そして#74738。2.1.201で3度目の再現が報告され、今度はXDG_DATA_HOME環境変数が空文字または相対値になっている場合に確実に再現する、という具体的なトリガーまで特定された。Anthropicのエンジニアからも「2.1.233で再現を確認した」というコメントが付き、XDG_DATA_HOMEを空文字にすると相対パスの計算がずれ、claude/versions/という迷子ディレクトリができて症状が再現するところまで技術的に裏付けられている。

それでもこのIssueは2026年9月15日、3度目の「長期間反応がないため自動クローズ」で閉じられた。翌日、別のユーザーが「このIssueは再現手順・バージョン情報が揃っているのに不当にクローズされている」とコメントを残し、stale bot自体の運用を問題視するメタIssue(#87647)を引用している。つまり、原因はほぼ特定されているのに、修正コミットが入る前にボットがIssueを閉じてしまうというプロセス上の問題が、実際の不具合修正よりも先に進んでしまっている状態だ。

Claude Codeで「command not found: claude」——インストールは成功してるのに動かない理由
Claude Codeで「command not found: claude」——インストールは成功してるのに動かない理由Claude Codeをインストールしたのに「command not found: claude」「is not recognized」と出る原因をPATH・複数インストールの競合・VS Code拡張機能の落とし穴に分けて解説。macOS/Linux/Windows別のコマンド付き。読む →

「command not found」系の不具合は他にもいろいろな原因があるが、上の記事で扱っているのはPATHが通っていない・複数インストールが競合している、といったユーザー側の環境要因が中心だ。今回のELOOPはそれとは別枠で、インストーラー自身がリンクを壊すという、こちらでは対処しきれない種類の不具合になる。

XDG_DATA_HOMEを確認する——再発を防ぐためにできること

#74738のやり取りで特定された発生条件は明確で、XDG_DATA_HOMEが「空文字」または「相対パス」になっていることだった。まず自分の環境がこの条件に当たっていないか確認する。

echo "${XDG_DATA_HOME+set:}$XDG_DATA_HOME"

何も表示されない、またはset:の後に何も続かない(空文字)場合、あるいは/から始まらない相対パスが表示される場合は、このバグのトリガーを踏んでいる可能性がある。

XDG_DATA_HOMEはXDG Base Directory仕様で定義された環境変数で、本来は「未設定なら無視してデフォルト値(~/.local/share)を使う」という仕様になっている。Claude Codeのインストーラーは、この変数が「未設定」であることは正しく処理できるが、「設定されているが値が空文字」というケースをうまく扱えず、結果として相対パスの計算がずれてしまう。これが3つのIssueに共通する根本原因という見立てだ。

対処は次のどちらかになる。

# パターン1: 未設定にする(dotfilesでexport XDG_DATA_HOME=""のような行があれば削除する)
unset XDG_DATA_HOME

# パターン2: 明示的に絶対パスを指定する
export XDG_DATA_HOME="$HOME/.local/share"

.bashrcや.zshrc、あるいはDockerやCI環境の設定でXDG_DATA_HOMEを空文字にしている記述がないか、一度grepで洗い出しておくと安心だ。

grep -rn "XDG_DATA_HOME" ~/.bashrc ~/.zshrc ~/.profile ~/.config/environment.d/ 2>/dev/null

npmインストールに切り替えるという選択肢

そもそもネイティブインストーラー自体がまだこの手の不具合を抱えている以上、Linux環境で運用の安定性を優先するなら、npm経由のグローバルインストールに切り替えるのも現実的な選択肢だ。

npm install -g @anthropic-ai/claude-code@latest

npmインストールはnode_modules配下にバイナリを展開する方式で、今回のような~/.local/binのシンボリックリンク自己参照は発生しない(そのかわりNode.jsのバージョン管理ツール絡みの別の落とし穴があるので、そちらは別記事を参照してほしい)。

Claude Codeで`claude update`が「成功」と出るのにバージョンが変わらない——反映されないアップデートの正体
Claude Codeで`claude update`が「成功」と出るのにバージョンが変わらない——反映されないアップデートの正体Claude Codeのclaude updateが成功と表示されるのにバージョンが変わらない・アップデートできない原因を、複数インストールの競合・npm権限エラー・自動更新の設定に分けて解説。診断コマンドと対処法つき。読む →

チームで特定バージョンに固定して運用している場合、バージョン切り替えの発生自体を減らすことも間接的な回避策になる。

Claude Codeを前のバージョンに戻す方法——ダウングレードと`claude install`、二度と壊れないためのバージョン固定
Claude Codeを前のバージョンに戻す方法——ダウングレードと`claude install`、二度と壊れないためのバージョン固定Claude Codeがアップデート後に不安定になったときの戻し方を解説。claude installコマンドでの特定バージョンへの切り替え、npm/Homebrew別の手順、autoUpdatesChannelとminimumVersionでの固定、ダウングレードすべきか迷ったときの判断基準までまとめた。読む →

FAQ

claude doctorを実行すればこの症状は検出できる?

claude doctor自体がシンボリックリンク経由のclaudeコマンドとして起動できない状態になっているため、claude doctorを実行しようとしても同じELOOPで失敗する。診断コマンドを使う前に、まず本記事の応急処置でシンボリックリンクを直接張り替える必要がある。

npmインストールとネイティブインストーラーが両方入っている場合は?

which -a claudeで複数のパスが出てくる場合、シェルのPATH優先順位次第でどちらが呼ばれるか変わる。片方が壊れていても、たまたまもう片方が先にヒットして症状に気づかないケースもある。両方入れているなら、片方(できればnpm経由)に統一したほうがトラブルシュートが楽になる。

WSL2でも同じ症状が起きる?

WSL2はLinuxカーネル上で動くディストリビューションなので、ネイティブインストーラーを使っていれば理論上同じ経路で発生し得る。ただしWSL2固有の別の不具合(/mnt/c配下のマウント絡みなど)と症状が混同されやすいので、まずはls -la ~/.local/bin/claudeでリンク先が相対パスの自己参照になっていないか、素直に目視確認するのが早い。

macOSでも起きるバグ?

これまで報告されている3件はすべてLinux(standalone/nativeインストーラー)環境からの報告で、macOSでの再現報告は確認できていない。macOSのインストーラーはHomebrewやアプリバンドル経由の配布経路が中心で、この~/.local/binのシンボリックリンク管理とは実装が異なるためと見られる。

まとめ

claudeコマンドがtoo many levels of symbolic linksで動かなくなる不具合は、ネイティブインストーラーがバージョン切り替え時に~/.local/bin/claudeを相対パスの自己参照シンボリックリンクとして書き込んでしまうことが原因だ。2026年4月の#45260を皮切りに、5月の#62822、7月の#74738と3回にわたって報告されながら、いずれも「再現手順・原因の見立てあり」の状態でstale botに自動クローズされ、根本修正には至っていない。

XDG_DATA_HOMEが空文字や相対パスになっているとトリガーになりやすいことは#74738のやり取りでほぼ特定されているので、心当たりがある人は環境変数を見直しておくと再発率を下げられる。今この症状に当たっている人は、まず~/.local/bin/claudeを絶対パスで張り替えて動く状態に戻し、そのうえでXDG_DATA_HOMEを確認する、という順番で対処するのが早い。

← 記事一覧に戻る