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
sandbox内のBashが初めて動く
Linuxでbubblewrapを使う環境で、gitリポジトリの中でsandbox付きのBashコマンドを実行します。
- 2
1バイトのファイルができる
メインの
.gitにcommondirが作られます。中身は.の1バイトで、sandbox内では読み取り専用でbind mountされます。書き込み保護のための目印のように見える、とissueは書いています。 - 3
終了後もファイルが残る
Claude Codeを終了しても、ホスト側に同じ1バイトのファイルが残ります。
- 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/commondirod -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が原因かの切り分け
- Qエラーに Empty 'commondir' file が含まれるか?答えが別の原因です。エラー全文から探してください。答えがはい
- Q.git/commondir が .git 直下にあり、中身は「.」だけか?答えがリンクされたworktree側の問題かもしれません。答えがはい
- 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が勧める手順ではなく、構成上の一案です。
参照した一次ソース
この記事の記述は、次の一次ソースと照合しています。更新時に参照先が変わった場合は一覧も更新します。