Claude Media
Claude Codeのsandboxでcommondirが「.」になりSpotlessが落ちる

Claude Codeのsandboxでcommondirが「.」になりSpotlessが落ちる

Linuxのsandbox実行後に.git/commondirが「.」で残り、gitは動くのにSpotlessなどJGit系ツールがEmpty 'commondir' fileで落ちる症状と、確認方法・回避策をまとめます。

Linuxでsandboxを有効にしたClaude Codeを動かしたあと、./gradlew spotlessApplyがEmpty 'commondir' fileで止まるなら、原因はsandboxが残した.git/commondirです。gitは普通に動くので気づきにくく、JGitを使うツールだけが落ちます。

この症状は2026年10月27日にClaude Codeのリポジトリへ報告されました(issue 105401、報告時のバージョンは2.1.311)。

どんな症状か

報告者の環境では、Gradle用のSpotlessが次のエラーでビルドを止めました。

> Could not create task ':spotlessJava'.
   > java.io.IOException: Empty 'commondir' file: /work/repo/.git/commondir

見るべき手がかりは.git/commondirというパスです。このファイルは本来、リンクされたworktreeのgitディレクトリ(.git/worktrees/<name>/)にある設定です。通常のリポジトリの.git直下には存在しません。

何が起きているのか

issueの記述をまとめると、流れは次のとおりです。

手順

commondirが残るまでの流れ

  1. 1

    sandbox内のBashが初めて動く

    Linuxでbubblewrapを使う環境で、gitリポジトリの中でsandbox付きのBashコマンドを実行します。

  2. 2

    1バイトのファイルができる

    メインの.gitにcommondirが作られます。中身は.の1バイトで、sandbox内では読み取り専用でbind mountされます。書き込み保護のための目印のように見える、とissueは書いています。

  3. 3

    終了後もファイルが残る

    Claude Codeを終了しても、ホスト側に同じ1バイトのファイルが残ります。

  4. 4

    JGit系ツールだけが拒否する

    gitはcommondirの.を「gitディレクトリ自身」と読むので動き続けます。JGitはこのファイルを空とみなして例外を投げます。

同じsandboxが作る.bashrc、.bash_profile、.gitconfigは終了時に消えますが、.git/commondirだけは残る、と報告者は指摘しています。

自分の環境で起きているか確かめる

条件はLinux(またはWSL2)でsandboxが有効なことです。macOSでの報告ではありません。次の2コマンドで状態を見られます。

ls -la .git/commondir
od -c .git/commondir

od -cの出力が.の1文字だけなら、issueと同じ状態です。リンクされたworktreeではないのにcommondirがメインの.gitにある、という点が目印になります。

sandbox内から見るなら、issueはgrep commondir /proc/self/mountinfoを使っています。読み取り専用のbind mountとして表示されれば、sandboxが保護している最中です。

回避策

Spotlessの行末設定を固定する

issueが示す回避策です。Spotlessは行末を決めるためにJGitでリポジトリを読みます。lineEndingsを明示すると、リポジトリを開かなくなり、sandboxの内外どちらでもビルドが通ったと報告されています。

spotless {
  lineEndings = 'UNIX'
}

Spotlessのドキュメントによると、lineEndingsの既定値はGIT_ATTRIBUTES_FAST_ALLSAMEで、固定値に変えることは強く勧められていません。gitの設定とSpotlessの判断がずれると面倒になるためです。UNIXに固定する前に、チームの.gitattributesが* text eol=lfのような設定かを確認してください。Windows改行を使うファイルを含むリポジトリでは、この回避策で改行が変わる可能性があります。

全プロジェクトに効かせるinitスクリプト

報告者はCIの全ビルドに対して、~/.gradle/init.dにinitスクリプトを置いています。

allprojects {
  plugins.withId('com.diffplug.spotless') {
    spotless { lineEndings = 'UNIX' }
  }
}

ビルドファイルを触れない場合や、複数リポジトリで同じ症状が出る場合に向く形です。

gradlewをsandboxの対象から外す

lineEndingsを固定できない事情がある場合は、Gradleの呼び出しそのものをsandboxの外で動かす手もあります。sandboxingのドキュメントには、sandbox.excludedCommandsに書いたコマンドパターンに一致する呼び出しをsandbox外で実行する設定があります。

{
  "sandbox": {
    "enabled": true,
    "excludedCommands": ["./gradlew *"]
  }
}

ドキュメントが挙げる条件は4つです。

  • パターンはBash(...)の許可ルールと同じ書き方で、ワイルドカードが無いと完全一致になる。./gradlewだけでは引数なしの呼び出しにしか当たらないので、末尾に *を付ける
  • 1回の呼び出しに複数のコマンドがつながっている場合は、すべてが一致しないとsandboxに残る。./gradlew build && ./gradlew spotlessCheckなら、両方が対象になる書き方が要る
  • 照合されるのは呼び出しの文字列そのもの。スクリプトやmakeのターゲットの中からgradlewを呼ぶ形は、一致しない
  • リダイレクト、cd、$(...)を含む呼び出しはsandboxに残る

外れたコマンドはファイルシステムの制限もネットワークのプロキシも受けません。ドキュメントは、信頼できて、sandbox内では動かないツールに使う手段として説明しています。書き込み先を足せば足りるツールなら、allowWriteのような許可の追加で済ませる方が、sandboxを保てます。今回の症状は、allowWriteが書き込み先を増やす設定で、すでに残ったcommondirは消せないため、書き込みの許可を足しても直りません。

これで外せるのは「そのgradlew呼び出し」だけです。同じセッションで別のsandbox付きBashがすでにcommondirを作っていれば、ファイルは残ったままで、外れたgradlewはそれをJGitで読んで落ちます。lineEndingsの固定は、ファイルの有無を問わず通ります。excludedCommandsは、commondirが作られていない状態でしか効きません。

リポジトリ側のsettingsにこの設定を書いても、管理者がallowUnsandboxedCommandsをmanaged settingsや--settingsでfalseにしたsandboxでは、リポジトリのexcludedCommandsは無視されます。CIでは、設定がどの層から来ているかも確かめてください。

ファイルを手で消す場合の注意

.git/commondirを消せばJGitは読めるようになります。ただし別のissue(103098)では、Windows版Claude Desktopで同種のプレースホルダを外から消しても、数秒で戻ってきたと報告されています。Linuxでも、次にsandbox付きのコマンドが動けば作り直される可能性があります。消す方法は、sandboxを使わないステップでのビルドの直前に限った一時しのぎです。

影響が出やすいのはどこか

issueの報告者がこの症状に当たったのは、GitHub Actions上でclaude-code-actionを動かす構成でした。環境変数CLAUDE_CODE_SUBPROCESS_ENV_SCRUB=1を設定していて、Claudeが実行した./gradlew spotlessApplyがすべて失敗したそうです。

環境変数のドキュメントでは、LinuxでCLAUDE_CODE_SUBPROCESS_ENV_SCRUBを設定したセッションでは、シェルモードのコマンドを含めすべてのコマンドがsandbox内で動くと説明されています。CIでこの変数を使うと、sandboxを意識しなくても毎回この経路に入る点が、気づきにくさの理由になります。

条件

影響を受けやすい条件

  • OSとsandbox

    Linux(報告ではAmazon Linux 2023)でbubblewrapとsocatを使うsandboxが有効なこと。

  • JGitを使うツール

    SpotlessのGradleプラグインのように、JGitでリポジトリを読むツール。issueでは6.13.0と8.10.4の両方で失敗しています。

  • 同じチェックアウトを使い回す

    sandbox内だけでなく、その後に同じチェックアウトで走るビルドも失敗します。

公式ドキュメントには何が書いてあるか

sandboxingのドキュメントは、保護パスとして作業ディレクトリ内の.git/hooksと.git/configを挙げています。.git/commondirは一覧に載っていません。Linuxでは、まだ存在しないファイルへの書き込み拒否を保つために、0バイトの読み取り専用プレースホルダを作り、sandboxが後で消すとも書かれています。

ただし、ドキュメントが説明しているのは0バイトのファイルが.claudeの設定パスに残るケースです。今回のcommondirは1バイトで内容が.のため、同じ仕組みの話かどうかはドキュメントからは分かりません。そのうえ、claude doctorが検出するのは残った設定パスのプレースホルダとして説明されています。commondirが検出対象に入るかどうかは、ドキュメントに記載がありません。

関連する症状の整理はClaude Codeのsandboxでgit addが失敗する原因と回避策に、プレースホルダの置かれ方の背景がまとまっています。sandboxのgit関連の別症状はClaude Codeのsandboxでgit SSHだけ失敗する原因と対処(macOS)にあります。

切り分けの順番

Spotless以外でも、JGitを使うツールなら同じ形で落ちます。ツール名に頼らず、エラー文言から入るのが早い道です。

切り分け

commondirが原因かの切り分け

  1. Qエラーに Empty 'commondir' file が含まれるか?
    答えが別の原因です。エラー全文から探してください。
    答えがはい
  2. Q.git/commondir が .git 直下にあり、中身は「.」だけか?
    答えがリンクされたworktree側の問題かもしれません。
    答えがはい
  3. QLinuxでsandboxが有効か?
    答えがこの症状の報告条件から外れます。
    答えがはい

issue 105401と同じ症状です

SpotlessならlineEndingsを固定するか、JGitを使わない手段で回します。修正の有無はissueで確認できます。

修正を待つあいだの運用

issueは「sandboxが他ツールとgitで解釈が分かれるファイルを作らず、残さないでほしい」と求めています。修正方針とバージョンは、コメントがまだ0件で、示されていません。修正されるまでは、使うバージョンで再現するかを確かめたうえで、上のlineEndings固定をCIの共通設定に入れておくのが現実的です。

JGit経由でリポジトリを読むツールをCIで使うチームは、sandbox内で動かすステップと、そうでないステップを分ける案もあります。分け方としては、上のexcludedCommandsに./gradlew *を入れて、Gradleの呼び出しだけをsandbox外に出す形が、設定のうえでは最も小さな変更です。ただし、先にsandbox内のステップがcommondirを作ると外のステップも落ちるので、ステップごとに別のチェックアウトを使う場合か、lineEndingsの固定と組み合わせる場合に限った案です。これはissueが勧める手順ではなく、構成上の一案です。

参照した一次ソース

この記事の記述は、次の一次ソースと照合しています。更新時に参照先が変わった場合は一覧も更新します。

  1. github.com/anthropics/claude-code/issues/105401
  2. github.com/anthropics/claude-code/issues/103098
  3. code.claude.com/docs/en/sandboxing
  4. github.com/diffplug/spotless/blob/main/plugin-gradle/README.md
この記事を共有:XはてブLinkedIn