Claude Media
Refusing to read symlink resolution changedの意味と対処

Refusing to read symlink resolution changedの意味と対処

Claude Codeに出るRefusing to readの意味を解説します。権限チェック後にsymlinkの解決先が変わると読み取りを拒否する仕組みと、繰り返すときの調べ方です。

Refusing to read <path>: its symlink resolution changed after permission was checked は、Claude Codeがファイルを開く直前に「権限チェックで承認したときと、パスの行き先が違う」と判断して、読み取りそのものを実行しなかったことを示す表示です。ファイルの中身は読まれていません。

メッセージはツールの結果としてClaudeに返ります。原文は次の形です。

Refusing to read /path/to/file: its symlink resolution changed after permission was checked (a link on the way now leads somewhere the check did not see). If a link in the working directory is being rewritten concurrently, stop that and retry.

後半の「作業ディレクトリ内のリンクが並行して書き換えられているなら、それを止めて再試行する」が、公式が示す基本の対処です。

権限チェックのあとに、開く瞬間にもう一度確かめる

Claude Codeはファイルパスに対して権限ルールを照合し、そのあとツールがファイルを開く時点、または検索を始める時点でも、パスの解決先を確認し直します。承認した場所と同じ場所を指していると確認できなければ、リンクをたどらずに拒否します。

パスにシンボリックリンクが含まれる場合、権限チェックは2つのパスを見ます。Claudeが要求したパスと、それが解決される実ファイルです。許可ルールは両方が一致したときだけ当てはまり、拒否ルールはどちらかが一致すれば当てはまります。

この仕組みが必要になる理由は、チェックと実行のあいだに時間差があることです。チェックの時点では作業ディレクトリ内の無害なファイルを指していたリンクが、開く直前に別の場所へ張り替えられると、承認した範囲の外を読んでしまいます。チェック時と使用時のずれを突くこの種の問題はTOCTOU(time-of-check to time-of-use)と呼ばれます。開く瞬間の再確認は、そのずれを閉じるための動作です。

くらべる

再確認がある場合とない場合

書き込みだけ

v2.1.251より前

再確認は書き込みに限られていました。承認後にリンクが差し替わると、読み取りや検索は別の場所に向かっても、メッセージは出ませんでした。

読み取り・検索も

v2.1.251以降

読み取りと検索も、開く瞬間に解決先を確かめます。食い違えば Refusing to read や Refusing to search で止まります。

このメッセージは不具合ではなく、v2.1.251で追加された確認が働いた結果です。

文言ごとに止まっている理由が違う

Refusing to で始まる表示は1種類ではありません。同じ節に載っている文言を、対象ツールと状況で分けます。

文言の後半対象起きていること
its symlink resolution changed after permission was checked対象読み取り・検索起きていることパス上のリンク、または検索の起点がチェック後に差し替わった
its parent-directory symlink resolution changed ...対象書き込み起きていること書き込み先の途中にあるディレクトリの解決先が、承認時と変わった
where it leads on disk could not be determined対象読み取り・書き込み起きていることリンクが循環するなどして、最終的な行き先をたどれない
it is a symbolic link. Write to the link's target path instead対象書き込み起きていること書き込み先そのものがリンクで、リンク先のパスを使うよう案内している
its permission check expired before it ran ...対象ファイル操作全般起きていること同時のファイル操作が多く、承認の記録が使われる前に破棄された

最初の行が、このページで扱う文言です。読み取りの拒否では、括弧の中の語句が「どの比較に失敗したか」を表します。errorsページには括弧内の語句を列挙した表がありません。実際に出た文面をそのまま控えておくと、再現や問い合わせのときに役立ちます。

文言が permission check expired のときは、リンクが原因ではありません。ファイル操作が同時に多数走ったことで承認の記録が先に破棄された状態で、再試行すると権限チェックが新しくやり直されます。

落とし穴

書き込み系の文言を読み取りの問題と取り違える

Refusing to write <path>: it is a symbolic link は、CLAUDE.md が AGENTS.md へのシンボリックリンクになっているときなどに出ます。これは差し替えの検知ではなく、リンク先のパスへ書くよう促す案内です。リンクが書き換わっていなくても出るため、原因探しを始める前に、読み取りの拒否か書き込みの拒否かを見分けます。

自分の環境で出たときの切り分け

読み取りの拒否は、頻度で原因が分かれます。1回だけなら一過性の差し替え、同じパスで繰り返すなら誰かがリンクを書き換え続けています。次の順に確かめます。

切り分け

Refusing to readが出たときの確かめ順

  1. Q同じパスで繰り返し出ているか?
    答えがいいえ

    一度きりなら、公式の案内どおり何もしなくて構いません。拒否された操作は実行されておらず、結果はClaudeに返っています。もう一度読ませれば、新しい権限チェックが走ります。

    答えがはい
  2. Qビルドツールやファイル監視がそのディレクトリを触っているか?
    答えがいいえ

    リンクを張り替える主体が見つからなければ、パスのどこがリンクかを調べます。次節のコマンドで、途中にあるリンクと行き先を一覧にします。

    答えがはい
  3. QmacOS以外か、または自分で書き換えたと分かっているファイルか?
    答えがいいえ

    macOSでドラッグしたスクリーンショットのように、システムが1つのファイルを2つのパスで報告する場合は、読み取りが拒否される不具合がありました。v2.1.273で修正されたので、更新します。

    答えがはい

リンクの張り替え元を止めるか、実パスを渡す

張り替えている主体を止めるか、Claudeに実ファイルのパスで読ませます。どちらも、リンクを経由しないため再検査と食い違いません。

Windowsでは別の症状もあります。AppContainerまたは制限付きトークンのサンドボックス内でClaude Codeを動かしていると、すべてのファイルで同じ拒否が出る不具合があり、v2.1.265以降で修正されています。1ファイルではなく全ファイルで出るなら、まずバージョンを確かめます。

繰り返すときの調べ方と、実パスで読ませる方法

パスの途中に何があるかは、シェルから確かめられます。次のコマンドは、対象ファイルの実体と、作業ディレクトリ内のリンクを一覧にします。<path> は拒否されたパスに置き換えてください。

realpath <path>
ls -ld <path>
find . -type l -ls

realpath の結果と元のパスが違えば、途中にリンクがあります。find . -type l -ls は、作業ディレクトリ配下のリンクとその向き先を並べます。同じリンクの向き先が時間をおいて変わるなら、張り替えている主体がいます。公式は例として、ビルドツールとファイル監視を挙げています。

張り替えを止められない場合は、Claudeへの指示で実パスを渡します。例えば次のような形です。

./current/report.md は symlink です。realpath で実体のパスを調べて、
そのパスを指定して読み直してください。

実体のパスで読めば、再確認の対象となるリンクを経由しません。ただし実体が作業ディレクトリの外にあると、許可ルールが両方のパスの一致を求めるため、別の許可が要ります。実体パスを Read ルールに書くときの起点の違いは、/path と //path の違いを扱った記事にあります。

版ごとに変わってきた拒否の範囲

この拒否は、一度にできたものではありません。変更履歴から、読み取りの拒否に関わる版を並べます。

あゆみ

symlink再確認の追加と修正

  1. v2.1.251読み取り・検索にも再確認を追加

    権限チェック後に差し替えられたリンクを、ファイルツール(Read、Write、Edit)がたどる問題を修正しました。この版の全体像はv2.1.251の記事にあります。GrepとGlobの検索起点にもReadのdenyルールが当たるようになりました。

  2. v2.1.265Windowsサンドボックスの全拒否を修正

    AppContainerや制限付きトークンのサンドボックス内で、Read、Write、Editが全ファイルを拒否する不具合が直りました。

  3. v2.1.273macOSのスクリーンショットを修正

    ドラッグして取り込んだスクリーンショットなど、システムが2つのパスで報告するファイルの読み取り拒否が直りました。

  4. v2.1.280行き先を特定できない拒否が登場

    where it leads on disk could not be determined の拒否は、この版から表示されます。

別の警告との見分け方

シンボリックリンクと権限の話は、他のメッセージとも並んで出ます。名前が近いものを分けておきます。

  • is not matched by file permission checks: 起動時の警告で、Write や NotebookEdit に書いたルールが参照されない設定上の問題です。書き換え先は専用の記事で扱っています
  • Refusing to read 系: 実行時に、特定のファイル操作が拒否された結果です。設定の誤りではなく、そのときのパスの状態が原因です

前者は設定ファイルを直すことで消え、後者は設定を触っても消えません。リンクの状態か、張り替えている主体を見ます。

symlinkを通した権限判定は、その後もv2.1.268でdeny・askルールの適用範囲が広がりました。経緯はv2.1.268の記事にあります。リンクそのものを作れないworktreeの失敗は、worktree作成のsymlink失敗が別の原因を説明しています。

対処のまとめ

拒否は一度なら実害がありません。操作は実行されず、結果がClaudeに返るだけです。繰り返すときはリンクを張り替えている主体を探して止め、止められないときは実パスで読ませます。Windowsで全ファイルが拒否されるなら、v2.1.265以降へ更新します。macOSで何も書き換えていないのに出るなら、v2.1.273以降です。

この記事を共有:XはてブLinkedIn