GitHub Actionsの別ジョブでビルド成果物が見つからない原因と受け渡し方法

GitHub Actionsでビルドしたdistや実行ファイルが次のジョブに存在しない場合、原因はジョブ間で作業フォルダーが自動共有されないことです。生成側のジョブでactions/upload-artifactを使って成果物を保存し、受取側のジョブでactions/download-artifactを使って取得します。

受取側にはneedsも指定します。ただし、needsが制御するのはジョブの実行順序であり、ファイル自体をコピーする機能ではありません。また、依存ライブラリを再利用するキャッシュと、デプロイ対象を受け渡すワークフローアーティファクトは用途が異なります。([GitHub Docs][1])

目次

GitHub Actionsの別ジョブで生成ファイルが見つからない理由

同じジョブ内のステップは同じ作業環境を使うため、前のステップで作成したファイルを後続ステップから参照できます。

一方、別のジョブに移ると、前のジョブで使っていた作業フォルダーは引き継がれません。たとえば、次のような構成ではdeployジョブにdistは存在しません。

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - run: npm run build

  deploy:
    runs-on: ubuntu-latest
    steps:
      - run: ls dist

actions/checkoutdeployジョブでも実行したとしても、取得できるのはリポジトリに登録されたソースコードです。buildジョブが実行中に生成したdistまでは復元されません。

ファイルを別ジョブへ渡すには、次の流れを明示的に作ります。

buildジョブ
  ↓ ビルド
dist/
  ↓ upload-artifact
GitHub上のワークフローアーティファクト
  ↓ download-artifact
deployジョブのrelease/
  ↓
デプロイ

アーティファクトとキャッシュは使い分ける

GitHub Actionsにはファイルを保存する仕組みとして、アーティファクトとキャッシュがあります。しかし、両者は置き換え可能な機能ではありません。

項目ワークフローアーティファクトキャッシュ
主な目的ジョブが生成したファイルの保存・受け渡しワークフローの高速化
代表例dist、実行ファイル、パッケージ、テスト結果npm、Maven、Gradleなどの依存ファイル
取得方法名前や実行IDを指定して明示的にダウンロードキャッシュキーを照合して復元
見つからない場合必要な成果物がなければ処理を失敗させるべき再ダウンロードや再生成できる設計にする
デプロイ対象への適性適している適していない

キャッシュは、見つからなくても依存ファイルを再取得できることが前提です。反対に、デプロイするファイルは「このビルドで生成したもの」を確実に使う必要があります。そのため、distやバイナリの受け渡しにはアーティファクトを使用します。([GitHub Docs][2])

同一ワークフロー内で成果物を受け渡す設定例

以下は、Node.jsプロジェクトでnpm run buildを実行するとdistが生成される場合の例です。

アクションのメジャーバージョンは更新されるため、実際に導入するときは各アクションの公式READMEと使用中のランナー環境を確認してください。次の例では、公式READMEに掲載されているGitHub.com向けのバージョンを使用しています。

name: Build and deploy

on:
  push:
    branches:
      - main

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout repository
        uses: actions/checkout@v6

      - name: Setup Node.js
        uses: actions/setup-node@v7
        with:
          node-version: '24'
          cache: 'npm'

      - name: Install dependencies
        run: npm ci

      - name: Build
        run: npm run build

      - name: Verify build output
        shell: bash
        run: |
          test -d dist
          find dist -maxdepth 2 -type f -print

      - name: Upload build artifact
        uses: actions/upload-artifact@v7
        with:
          name: web-dist
          path: dist/
          if-no-files-found: error
          retention-days: 7

  deploy:
    needs: build
    runs-on: ubuntu-latest

    steps:
      - name: Checkout deployment scripts
        uses: actions/checkout@v6

      - name: Download build artifact
        uses: actions/download-artifact@v8
        with:
          name: web-dist
          path: release/

      - name: Verify downloaded files
        shell: bash
        run: |
          test -d release
          find release -maxdepth 2 -type f -print

      - name: Deploy
        run: ./scripts/deploy.sh release/

最後の./scripts/deploy.sh release/は説明用です。実際には、利用しているクラウドサービスやサーバーに応じたデプロイコマンドへ置き換えます。

生成側ではnameとpathを正確に指定する

upload-artifactで特に重要なのは、namepathです。

- name: Upload build artifact
  uses: actions/upload-artifact@v7
  with:
    name: web-dist
    path: dist/
    if-no-files-found: error

nameは受け渡し用の識別名

nameは、受取側が目的のアーティファクトを指定するときに使用します。

name: web-dist

ダウンロード側にも、同じ名前を指定します。

name: web-dist

web-distweb_distのように表記が異なれば、別の名前として扱われます。環境名やビルド対象を含める場合も、アップロード側とダウンロード側で完全に一致させてください。

マトリックスビルドでは、複数ジョブが同じ名前へアップロードしないようにします。

name: app-${{ matrix.os }}-${{ matrix.arch }}

現在のアーティファクトアクションでは、同じ名前のアーティファクトへ複数ジョブから追記する設計は避け、ジョブごとに一意な名前を付ける必要があります。

pathは実際の出力先に合わせる

ビルドツールによって出力フォルダーは異なります。

ツールや構成の例よくある出力先
Vitedist/
Create React Appbuild/
Next.jsの静的出力out/
.NETの発行処理指定したpublish/など
Javaのビルドtarget/またはbuild/libs/

思い込みでdist/を指定せず、ビルド直後に実際のパスを確認します。

- name: Inspect build output
  run: |
    pwd
    find . -maxdepth 3 -type f -print

本番運用ではログが長くなりすぎないよう、確認範囲を出力フォルダー周辺に絞ります。

ファイルがない場合は警告ではなく失敗させる

upload-artifactは、指定したパスにファイルがない場合の動作をif-no-files-foundで変更できます。

if-no-files-found: error

デプロイ用アーティファクトでは、空の成果物を残して処理を継続するより、ビルドジョブをその場で失敗させたほうが原因を特定しやすくなります。公式READMEではwarnerrorignoreが用意されています。

機密ファイルをアーティファクトへ含めない

アップロード対象をリポジトリ全体の.にすると、意図しないファイルまで保存される可能性があります。次のようなファイルは含めないでください。

  • .envや環境別の設定ファイル
  • SSH秘密鍵
  • クラウドサービスの認証キー
  • サービスアカウントのJSONファイル
  • 認証情報を含む.npmrc
  • デプロイ用アクセストークン
  • データベースの接続情報

デプロイに必要な認証情報はアーティファクトへ埋め込まず、GitHub ActionsのSecretsやEnvironmentから実行時に渡します。

複数のパスや除外パターンも指定できます。

- name: Upload files
  uses: actions/upload-artifact@v7
  with:
    name: web-dist
    path: |
      dist/
      !dist/**/*.map

ただし、ソースマップが障害調査に必要な構成もあります。機械的に除外するのではなく、公開範囲や保管先を考えて判断してください。

現在のupload-artifactには隠しファイルの包含を制御する設定がありますが、デフォルトの除外動作だけを機密情報対策にしないことが重要です。アップロード対象を必要最小限のフォルダーへ絞ってください。

受取側はneedsと同じアーティファクト名を指定する

受取側のジョブには、生成側への依存関係を指定します。

deploy:
  needs: build

これにより、deploybuildの正常終了後に開始されます。needsがない場合、両方のジョブが並行して開始される可能性があります。

ただし、needsだけではファイルは受け渡されません。別途download-artifactが必要です。

- name: Download build artifact
  uses: actions/download-artifact@v8
  with:
    name: web-dist
    path: release/

役割は次のように分かれます。

設定役割
needs: buildジョブの実行順序を制御する
name: web-dist取得するアーティファクトを特定する
path: release/ダウンロードしたファイルの展開先を指定する

ダウンロード後のフォルダー構造を確認する

単一のアーティファクトを名前で指定した場合、その内容はpathで指定したフォルダーへ直接展開されます。

たとえば、次の指定なら、ファイルは原則としてrelease/の直下へ展開されます。

with:
  name: web-dist
  path: release/

release/web-dist/が自動作成されると思い込むと、デプロイコマンドの参照先を間違えます。

一方、nameを省略して複数のアーティファクトをまとめて取得すると、標準ではアーティファクト名ごとのサブフォルダーが作成されます。

デプロイ処理を追加する前に、一度だけ構造を表示すると安全です。

- name: Inspect downloaded artifact
  run: find release -maxdepth 3 -type f -print

確認後は、必要に応じて表示範囲を狭めるか、このステップを削除します。

保存期限はretention-daysで指定する

アーティファクトごとの保存期限は、アップロード時のretention-daysで指定できます。

- uses: actions/upload-artifact@v7
  with:
    name: web-dist
    path: dist/
    retention-days: 7

ただし、指定できる日数はリポジトリ、組織、Enterprise側で設定された上限を超えられません。([GitHub Docs][1])

保存期間は、次の基準で決めます。

利用目的保存期間の考え方
同じワークフロー内で直後にデプロイするだけ短めでよい
数日後に手動で再デプロイする再実行する可能性がある期間を確保する
過去版へのロールバックに利用する運用上必要な世代を保持できる期間にする
長期配布する正式版アーティファクト以外の保管先も検討する

ワークフローアーティファクトは永続的な配布場所ではありません。長期保管が必要な実行ファイルやパッケージは、GitHub Releases、GitHub Packages、オブジェクトストレージなど、用途に合った保管先を検討します。

別の実行や別ワークフローから取得する方法

download-artifactは、指定がなければ現在のリポジトリにおける現在のワークフロー実行を対象にします。

別のワークフロー実行から取得する場合は、対象の実行IDと、必要なアクセス権を持つトークンを指定します。

- name: Download artifact from another run
  uses: actions/download-artifact@v8
  with:
    name: web-dist
    github-token: ${{ secrets.ARTIFACT_READ_TOKEN }}
    repository: example-org/example-repository
    run-id: 1234567890
    path: release/

各項目の意味は次のとおりです。

項目内容
github-token対象リポジトリのアーティファクトを読み取れるトークン
repository所有者名/リポジトリ名
run-idアーティファクトを生成したワークフロー実行のID
name取得するアーティファクト名
path展開先

run-idはジョブIDや連番表示用のrun_numberではありません。workflow_runイベントから取得する場合は、状況に応じて次の値を利用できます。

run-id: ${{ github.event.workflow_run.id }}

別リポジトリから取得する場合、トークンには対象リポジトリに対するactions:read相当の権限が必要です。非公開リポジトリでは、トークンを発行したユーザーやGitHub App自体が対象リポジトリへアクセスできなければ取得できません。

非公開アーティファクトのアクセス権と有効期限

非公開リポジトリのアーティファクトは、URLを知っているだけで誰でも取得できる公開ファイルではありません。ブラウザから取得する場合はログインとリポジトリへのアクセス権が必要です。

また、次のいずれかに該当すると取得できなくなります。

  • 保存期限を過ぎた
  • アーティファクトが削除された
  • 元のワークフロー実行が削除された
  • リポジトリが削除された
  • 使用するトークンに読み取り権限がない

アーティファクトURLも、アーティファクト、実行、リポジトリが存在し、必要なアクセス権がある間だけ利用できます。

GitHub.comとGitHub Enterprise Serverで同じ版を使わない

GitHub.comで動作するアクションの最新版が、GitHub Enterprise Serverでもそのまま使えるとは限りません。

現在の公式READMEでは、upload-artifactdownload-artifactの新しい系列について、GitHub Enterprise Serverでは未対応となる版があることが明記されています。GHESでは、サーバー側が対応する専用の版を選ぶ必要があります。

特に確認する項目は次のとおりです。

  • GitHub.comかGitHub Enterprise Serverか
  • 使用しているGHESのバージョン
  • GitHub-hosted runnerかself-hosted runnerか
  • アクションが必要とするNode.jsランタイム
  • self-hosted runnerの最低対応バージョン
  • 組織側で許可されているアクションとバージョン

GitHub.com向けの記事からYAMLをコピーしただけでは、GHESでUnable to resolve actionやランタイム関連のエラーになることがあります。各アクションのREADMEにある「GHES Support」と、自社環境の管理者向けドキュメントを確認してください。

よくあるエラーと確認ポイント

症状主な原因対処
No files were found with the provided pathビルド出力先とpathが一致していないビルド直後にpwdfindで確認する
Artifact not foundnameの不一致、別実行を参照、期限切れ名前、run-id、保存期限を確認する
ダウンロードは成功したがファイルが見つからない展開先の構造を誤認しているダウンロード直後にfindで確認する
デプロイがビルドより先に始まるneedsがないneeds: buildを指定する
別リポジトリから403や404になるトークンの権限不足対象リポジトリへの読み取り権限を付ける
GHESでアクションを解決できないGitHub.com向けの非対応版を使用しているGHES対応版へ変更する
ダウンロード後に実行ファイルを起動できない実行権限が保持されていないchmod +xを実行するか、事前にアーカイブする

通常の圧縮形式でアップロードした場合、ダウンロード後のファイル権限が元の状態と同じとは限りません。実行権限が必要なスクリプトやバイナリでは、再度chmodするか、権限を保持できる形式にまとめてからアップロードします。

まず修正するべき設定

ビルドしたファイルが次のジョブに存在しない場合は、次の順番で修正します。

  1. ビルド直後に、実際の出力フォルダーを確認する
  2. upload-artifactで名前とパスを指定する
  3. if-no-files-found: errorで空のアップロードを防ぐ
  4. 受取側へneeds: buildを追加する
  5. download-artifactで同じ名前を指定する
  6. ダウンロード先を明示し、直後にファイル構造を確認する
  7. 別実行から取得する場合だけ、トークンとrun-idを追加する
  8. 保存期限とGitHub.com・GHESの対応版を確認する

基本形は、生成側でアップロードし、依存関係を設定した受取側で同じ名前のアーティファクトをダウンロードすることです。キャッシュで代用せず、ビルド済み成果物を明示的に受け渡せば、デプロイジョブが別のランナーで実行されても同じファイルを利用できます。
[1]: https://docs.github.com/en/actions/tutorials/store-and-share-data “Store and share data with workflow artifacts – GitHub Docs”
[2]: https://docs.github.com/en/actions/concepts/workflows-and-actions/dependency-caching “Dependency caching – GitHub Docs”

この記事を書いた人

実務の現場で詰まりがちなポイントを地図にするITブログ「IT trip」を運営。Windows/Office(Teams・Excel)からSQL、サーバ運用、ガジェットまで、再現性のある手順と“なぜそうなるか”を丁寧に解説します。読んだらすぐ試せること、そして迷った人の次の一歩が見えることを大切にしています。

コメント

コメントする

目次