GitHub Actionsで「Argument list too long」エラーを解決する

2026-02-26 hit count image

モノレポCIで変更ファイルが多い場合に発生する「Argument list too long」エラーの原因と、 BashからJavaScript(actions/github-script)への切り替えによる解決方法を紹介します。

github_actions

問題の状況

モノレポ環境でCI/CDパイプラインを運用していると、予想外のエラーに遭遇することがあります。私たちのチームでも、GitHub ActionsのファイルチェックワークフローArgument list too longというエラーが発生しました。

このワークフローは、PRで変更されたファイルが該当サービスブランチで修正可能なファイルかどうかを検証する役割を持っています。例えば、service-aブランチではserviceAディレクトリのファイルのみ修正できるように制限するものです。

既存の実装はtj-actions/changed-filesで変更ファイル一覧を取得した後、Bashのforループで環境変数に渡されたファイルリストを巡回する方式でした。

for file in $ALL_CHANGED_FILES; do
  service_type=$(echo "$file" | cut -d'/' -f2)
  if [ "$service_type" != "$service_directory" ]; then
    echo "The file $file is not allowed to be changed in the $SERVICE_NAME branch."
    exit 1
  fi
done

問題は変更ファイル数が多い場合に発生します。$ALL_CHANGED_FILES環境変数に格納されたファイルパスがOSの引数長制限(Linuxの場合、デフォルトのARG_MAX = 約2MB)を超えるとArgument list too longエラーが発生します。モノレポの規模が大きくなるほど、1つのPRで数百、数千のファイルが変更されるケースが増え、この制限に引っかかりやすくなります。

解決方法

解決のポイントは2つです。

1. 変更ファイル一覧をファイルに保存

tj-actions/changed-fileswrite_output_filesオプションを活用して、変更ファイル一覧を環境変数の代わりにファイルに保存するように変更しました。

- name: Get changed files
  id: changed-files
  uses: tj-actions/[email protected]
  with:
    files: |
      **
    write_output_files: true
    output_dir: /tmp

これにより/tmp/all_changed_files.txtに変更ファイル一覧が記録されます。ファイルシステムを通じてデータをやり取りするため、OSの引数長制限の影響を受けません。

2. BashからJavaScriptへの切り替え

ファイルを読み込んで処理するロジックを、Bashの代わりにactions/github-scriptを使用したJavaScriptで書き直しました。

- name: Validate file changes
  uses: actions/github-script@v7
  with:
    script: |
      const fs = require('fs');

      const serviceDirectoryMap = {
        'service-a': 'serviceA',
        'service-b': 'serviceB',
        'service-c': 'serviceC',
        // ...
      };

      const serviceName = process.env.SERVICE_NAME;
      const serviceDirectory = serviceDirectoryMap[serviceName];
      // ...

      const fileContent = fs.readFileSync('/tmp/all_changed_files.txt', 'utf8');
      const files = fileContent.trim().split(/\s+/).filter(file => file.trim() !== '');

      for (const filename of files) {
        // 許可ファイルチェックとサービスディレクトリ検証
      }

この切り替えで得られたメリットは以下の通りです。

項目Bash(変更前)JavaScript(変更後)
ファイル一覧の受け渡し環境変数(長さ制限あり)ファイルI/O(制限なし)
サービスマッピングcaseオブジェクトリテラル(Map
エラーハンドリングexit 1core.setFailed()
可読性Shell特有の構文直感的なJavaScript

重要なポイント

環境変数で大量のデータを渡さないでください。 これはGitHub Actionsに限った問題ではなく、Unix/Linuxシステム全般に該当する制約です。シェルコマンドの引数長にはOSレベルの制限があり、CI環境で変更ファイル数が予測不可能な場合は、必ずファイルベースの受け渡し方式を使用すべきです。

また、actions/github-scriptはGitHub Actionsで複雑なロジックを処理する際のBashの良い代替手段です。Node.jsランタイム上で動作するため、fspathなどの標準モジュールを自由に使用でき、core.setFailed()のようなActions専用APIもすぐに活用できます。

まとめ

小さな修正ですが、CIパイプラインの安定性を大きく向上させた変更でした。モノレポの規模が大きくなるほど、このようなシステムレベルの制約に遭遇する可能性が高くなるため、「今は動いているから大丈夫」ではなく、スケーラビリティを考慮した設計が重要だということを改めて感じました。

ファイルチェックワークフローの全体構成について詳しく知りたい方は、モノレポでブランチごとにファイル変更範囲を制限するGitHub Actionsワークフローをご参照ください。

私のブログが役に立ちましたか?下にコメントを残してください。それは私にとって大きな大きな力になります!

アプリ広報

今見てるブログを作成たDekuが開発したアプリを使ってみてください。
Dekuが開発したアプリはFlutterで開発されています。

興味がある方はアプリをダウンロードしてアプリを使ってくれると本当に助かります。



SHARE
Twitter Facebook RSS