できない.dev

Gradle「./gradlew: Permission denied」の原因と直し方

./gradlew: Permission denied は、gradlew に実行権限を付ければ直る。
Windows で追加した gradlew は実行ビットなしで Git に記録されるので、git update-index --chmod=+x で記録し直す。

公開:

要約

Gradle Wrapper の gradlew を実行すると、Gradle が動く前にシェルが止める。
Gradle 9.8.1 の gradle wrapper で作った gradlew から実行ビットを外して、bash で実行すると次のように出た。

$ ./gradlew build
bash: ./gradlew: Permission denied
$ ls -l gradlew
-rw-r--r-- 1 user user 8656 Oct 20 01:01 gradlew

./gradlew: Permission denied は、gradlew に実行権限が無いという意味だ。
Gradle の設定やバージョンの問題ではない。
終了コードは 126 になる。gradlew はシェルスクリプトなので、実行ビット(x)が無いと ./gradlew の形では起動できない。

手元では動くのに CI だけで落ちるなら、Git に記録されている gradlew のモードを疑う。
公式ドキュメントのとおり Wrapper のファイルはリポジトリにコミットして共有するものなので(Gradle Wrapper(新しいタブで開く))、記録された時点で実行ビットが落ちていると、clone したすべての環境で同じエラーになる。

解決策

1. 手元で実行権限を付ける

chmod +x gradlew
./gradlew build

2. 実行ビットを Git に記録する

CI で落ちる場合は、手元の chmod だけでは直らない。git update-index --chmod=+x で、Git に記録されているモードを変えてコミットする(git-update-index(新しいタブで開く))。
Windows の Git(Git for Windows 2.48)でも、この方法で 100755 に変わった。

git update-index --chmod=+x gradlew
git ls-files -s gradlew
git commit -m "gradlew を実行可能にする"
git push

git ls-files -s gradlew の先頭が 100644 から 100755 に変われば記録できている。
コミットには mode change 100644 => 100755 gradlew と出る。
この後に clone し直した gradlew は -rwxr-xr-x になり、./gradlew --version が通った。

3. 権限を変えられないときは sh から起動する

読み取り専用の場所などで権限を変えられないときは、sh に gradlew を渡して起動する。
実行ビットの無い gradlew でも、sh gradlew --version は終了コード 0 で通った。

sh gradlew build

CI の設定に chmod +x gradlew のステップを足しても動くが、それは毎回の一時しのぎになる。
リポジトリ側の記録を直しておけば、どの環境でも ./gradlew のまま動く。

よくある原因

  1. Windows でコミットした。
    Windows の Git では、git init や git clone のときに core.fileMode が false に設定される(Git for Windows 2.48 で確認)。
    この設定のまま新しく追加したファイルは、ディスク上で実行可能かどうかに関係なく 100644(実行ビットなし)で記録される。
    Linux の Git で core.fileMode=false にして gradlew を追加したところ、実行可能な gradlew でも 100644 で記録された。
  2. それを clone した。
    記録が 100644 なら、Linux や macOS、GitHub Actions のような CI で clone した gradlew は -rw-r--r-- になる。
  3. 手元で実行ビットが外れた。
    ファイルのコピーや展開の仕方によっては、実行ビットが付かないことがある。

core.fileMode は、作業ツリーのファイルの実行ビットを Git が信用するかどうかの設定である(git-config(新しいタブで開く))。