diff --git a/errors/caching-artifacts/ca-146.yml b/errors/caching-artifacts/ca-146.yml new file mode 100644 index 0000000..8cea196 --- /dev/null +++ b/errors/caching-artifacts/ca-146.yml @@ -0,0 +1,127 @@ +id: ca-146 +title: 'download-artifact v4/v5 Fails with "Request timeout" When Downloading Large Artifacts from Blob Storage' +category: caching-artifacts +severity: error +tags: + - download-artifact + - artifact + - timeout + - blob-storage + - request-timeout + - transient + - large-artifact +patterns: + - regex: 'Unable to download and extract artifact: Request timeout:' + flags: 'i' + - regex: 'Unable to download artifact\(s\): Unable to download and extract artifact: Request timeout' + flags: 'i' + - regex: 'download and extract artifact.*Request timeout' + flags: 'i' +error_messages: + - 'Unable to download artifact(s): Unable to download and extract artifact: Request timeout: /actions-results/...' + - 'Error: Unable to download artifact(s): Unable to download and extract artifact: Request timeout' + - 'Request timeout: https://productionresultssa.blob.core.windows.net/...' +root_cause: | + `actions/download-artifact@v4+` downloads artifact content from Azure Blob Storage + via a time-limited SAS URL. When the artifact download takes too long — due to + large artifact size, network congestion between the GitHub Actions runner and Azure + Blob Storage, or throttling on the blob storage endpoint — the SAS URL's embedded + time window expires while the download is still in progress. + + The error manifests as a `Request timeout:` followed by the full blob storage URL + (including the expiring `se=` query parameter). This is distinct from: + - `Artifact download failed after N retries` — which covers retry exhaustion + - `Not a valid zip file` — which covers corrupt downloads + + The issue is intermittent: retrying the workflow often succeeds because a fresh SAS + URL with a new time window is generated. Large artifacts (typically >1 GB uncompressed + or >500 MB compressed) are most susceptible. GitHub-hosted runners in certain regions + can also experience higher latency to the blob storage endpoint. + + First reported widely in actions/download-artifact#249 (115 reactions). The root + cause is that the SAS URL timeout is calculated from the time the artifact download + request is initiated, not from the time the runner begins pulling bytes — so if the + runner is under load or the storage endpoint is slow to respond, the window can + close mid-download. +fix: | + There is no user-side configuration to extend the SAS URL timeout. Options: + + 1. **Re-run the failed job**: A fresh workflow run generates a new SAS URL with a + new time window. This is the simplest fix for transient occurrences. + + 2. **Reduce artifact size**: Split large artifacts into smaller named artifacts using + multiple `upload-artifact` steps and download them in parallel or sequentially. + Smaller artifacts are less likely to time out. + + 3. **Use `actions/cache` instead of artifacts** for build outputs that are only + consumed within the same workflow. Cache restores use the same blob backend but + have more lenient timeout handling. + + 4. **Check for runner resource contention**: Artifacts download over the runner's + network. If the runner is simultaneously performing other I/O-heavy operations, + the effective download bandwidth may be reduced. Isolate the download step. + + 5. **Upgrade to latest action version**: `actions/download-artifact@v5` and later + include improved retry logic and timeout handling compared to v4.x releases. +fix_code: + - language: yaml + label: 'Split large artifact into smaller named parts to reduce per-download size' + code: | + jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Build frontend + run: npm run build + + # Upload as separate smaller artifacts instead of one large one + - name: Upload dist/js + uses: actions/upload-artifact@v4 + with: + name: dist-js + path: dist/js/ + + - name: Upload dist/css + uses: actions/upload-artifact@v4 + with: + name: dist-css + path: dist/css/ + + deploy: + needs: build + runs-on: ubuntu-latest + steps: + # Download smaller artifacts separately — each less likely to timeout + - uses: actions/download-artifact@v4 + with: + name: dist-js + path: dist/js/ + + - uses: actions/download-artifact@v4 + with: + name: dist-css + path: dist/css/ + - language: yaml + label: 'Upgrade to latest download-artifact version with improved retry/timeout handling' + code: | + steps: + # Prefer latest version — v5+ has better timeout/retry logic than v4.x + - uses: actions/download-artifact@v5 + with: + name: my-artifact + path: artifacts/ +prevention: + - 'Keep individual artifact sizes under 500 MB compressed where possible to reduce timeout exposure' + - 'Use actions/cache instead of artifacts for inter-job data that does not need to persist beyond the workflow' + - 'Split large build outputs into multiple named artifacts and download them separately' + - 'Pin to the latest major version of download-artifact to get improved timeout handling' + - 'Add retry logic at the workflow level using continue-on-error and a subsequent re-download step as a fallback' +docs: + - url: 'https://github.com/actions/download-artifact/issues/249' + label: 'actions/download-artifact#249: Unable to download and extract artifact: Request timeout (115 reactions)' + - url: 'https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/storing-workflow-data-as-artifacts' + label: 'GitHub Docs: Storing workflow data as artifacts' + - url: 'https://github.com/actions/download-artifact' + label: 'actions/download-artifact — changelog and migration guide' diff --git a/errors/caching-artifacts/ca-147.yml b/errors/caching-artifacts/ca-147.yml new file mode 100644 index 0000000..8500aaa --- /dev/null +++ b/errors/caching-artifacts/ca-147.yml @@ -0,0 +1,124 @@ +id: ca-147 +title: '`deploy-pages@v4` Fails with "HttpError: No artifact_url provided" When Using Mismatched upload-pages-artifact Version' +category: caching-artifacts +severity: error +tags: + - deploy-pages + - upload-pages-artifact + - pages + - artifact-url + - version-mismatch + - HttpError + - github-pages +patterns: + - regex: 'HttpError: No artifact_url provided' + flags: 'i' + - regex: 'Creating Pages deployment failed' + flags: 'i' + - regex: 'Failed to create deployment \(status: 400\).*No artifact_url provided' + flags: 'i' +error_messages: + - 'Error: Creating Pages deployment failed' + - 'Error: HttpError: No artifact_url provided' + - "Error: Error: Failed to create deployment (status: 400) with build version . Responded with: No artifact_url provided" +root_cause: | + `actions/deploy-pages@v4` introduced a new GitHub Pages deployment API that requires + an `artifact_url` field in the deployment payload. This URL is produced by + `actions/upload-pages-artifact@v3` (and later) — older versions of the action + (`upload-pages-artifact@v1` and `v2`) do not generate this URL and instead use + the legacy artifact ID-based flow. + + When a workflow uses `deploy-pages@v4` together with `upload-pages-artifact@v1` + or `v2`, the deploy step fails with HTTP 400 because `artifact_url` is absent from + the payload that `deploy-pages` assembles from the prior step's outputs. + + The stack trace makes the cause look like an API error (`No artifact_url provided`) + rather than a version mismatch in the workflow, which makes it difficult to diagnose. + + Additionally, swapping ONLY `upload-pages-artifact` to `@v3` while keeping older + `deploy-pages` (v2 or v3) can also fail, because the upload and deploy actions must + be from compatible major version pairs: + - `upload-pages-artifact@v3` + `deploy-pages@v4` → compatible + - `upload-pages-artifact@v1`/`v2` + `deploy-pages@v4` → fails (No artifact_url) + - `upload-pages-artifact@v3` + `deploy-pages@v2`/`v3` → fails (format mismatch) + + Reported in actions/deploy-pages#284 (34 reactions). +fix: | + Always update `upload-pages-artifact` and `deploy-pages` together to matching + major versions. The compatible pairs are: + + - `upload-pages-artifact@v1` + `deploy-pages@v2` (legacy, no longer recommended) + - `upload-pages-artifact@v3` + `deploy-pages@v4` (current, recommended) + + Do not mix major versions between the two actions. +fix_code: + - language: yaml + label: 'BROKEN — upload-pages-artifact v1/v2 with deploy-pages v4 causes "No artifact_url"' + code: | + # BROKEN: mismatched versions + jobs: + deploy: + runs-on: ubuntu-latest + permissions: + pages: write + id-token: write + steps: + - uses: actions/checkout@v4 + + - name: Build site + run: npm run build + + # v1 does not produce artifact_url — incompatible with deploy-pages@v4 + - name: Upload pages artifact + uses: actions/upload-pages-artifact@v1 + with: + path: dist/ + + - name: Deploy to GitHub Pages + uses: actions/deploy-pages@v4 # v4 requires artifact_url from v3+ + - language: yaml + label: 'FIXED — upgrade both actions to their current compatible major versions' + code: | + # FIXED: matching major versions + jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Build site + run: npm run build + + # v3 produces the artifact_url field required by deploy-pages@v4 + - name: Upload pages artifact + uses: actions/upload-pages-artifact@v3 + with: + path: dist/ + + deploy: + needs: build + runs-on: ubuntu-latest + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + permissions: + pages: write + id-token: write + steps: + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 +prevention: + - 'Always bump upload-pages-artifact and deploy-pages together — they are a matched pair and must use compatible major versions' + - 'When updating one, immediately search your workflow for the other and update it in the same PR' + - 'Use the official GitHub Pages workflow starter template which keeps both actions in sync' + - 'Add a comment in your workflow noting the required version pairing to warn future maintainers' +docs: + - url: 'https://github.com/actions/deploy-pages/issues/284' + label: 'actions/deploy-pages#284: Actions fail after update to v4 and upload-pages-artifact v3 (34 reactions)' + - url: 'https://docs.github.com/en/pages/getting-started-with-github-pages/configuring-a-publishing-source-for-your-github-pages-site' + label: 'GitHub Docs: Configuring a publishing source for GitHub Pages' + - url: 'https://github.com/actions/deploy-pages/releases' + label: 'actions/deploy-pages — releases and migration notes' + - url: 'https://github.com/actions/upload-pages-artifact/releases' + label: 'actions/upload-pages-artifact — releases and migration notes' diff --git a/errors/runner-environment/re-489.yml b/errors/runner-environment/re-489.yml new file mode 100644 index 0000000..ade1988 --- /dev/null +++ b/errors/runner-environment/re-489.yml @@ -0,0 +1,130 @@ +id: re-489 +title: '`actions/checkout` Fails with "couldn''t find remote ref refs/pull/N/merge" for PRs with Merge Conflicts' +category: runner-environment +severity: error +tags: + - checkout + - pull-request + - merge-ref + - merge-conflict + - refs-pull-merge + - git + - draft-pr +patterns: + - regex: "fatal: couldn't find remote ref refs/pull/\\d+/merge" + flags: 'i' + - regex: 'refs/pull/\d+/merge.*not found|couldn.t find.*refs/pull/\d+/merge' + flags: 'i' + - regex: "Error: fatal: couldn't find remote ref refs/pull" + flags: 'i' +error_messages: + - "fatal: couldn't find remote ref refs/pull/123/merge" + - "Error: fatal: couldn't find remote ref refs/pull/123/merge" + - "fatal: repository 'https://github.com/...' not found" +root_cause: | + GitHub creates a virtual `refs/pull/{N}/merge` reference for each open pull request + to represent the result of merging the PR's head commit into the base branch. This + ref is useful for CI workflows that want to test the merged code (not just the PR + head) — it is commonly referenced as: + + ```yaml + uses: actions/checkout@v4 + with: + ref: refs/pull/${{ github.event.pull_request.number }}/merge + ``` + + However, GitHub only generates this virtual ref when the PR can be **cleanly merged** + into the base branch with no conflicts. In the following cases the ref does NOT exist: + + - The PR has **merge conflicts** with the base branch + - The PR is a **draft** and GitHub hasn't computed the merge result yet + - The PR was just opened and the merge ref hasn't been computed yet (brief race) + - The base branch was force-pushed after the merge ref was last computed + + When `refs/pull/N/merge` doesn't exist, `actions/checkout` calls `git fetch` for + that ref and git returns `fatal: couldn't find remote ref refs/pull/123/merge`, + causing the step — and by default the entire workflow — to fail. + + This is especially frustrating because the same workflow succeeds on clean PRs and + silently starts failing once a conflict is introduced, making the CI appear broken + for reasons unrelated to the code change. +fix: | + Option 1 (recommended): Check out the PR's HEAD ref (`refs/pull/N/head`) instead + of the merge ref. This always exists but tests the PR's code without the merge + applied. For most CI purposes this is sufficient. + + Option 2: Add a guard step that checks if the merge ref is reachable before + attempting to check it out, and fail with a clear message ("PR has merge conflicts, + please resolve before CI can test the merged result") instead of a cryptic git error. + + Option 3: Use `actions/checkout` default behavior (checkout the triggering SHA) + and skip the manual `ref:` override. The default checkout in a pull_request workflow + uses the merge commit if available, or the head commit if the merge ref is absent. + + Option 4 (for workflow_run or cross-event contexts): access the merge SHA via + `github.event.pull_request.merge_commit_sha` and check it is non-null before use. +fix_code: + - language: yaml + label: 'BROKEN — refs/pull/N/merge fails when PR has conflicts or merge ref not yet computed' + code: | + # BROKEN: fails silently when PR has merge conflicts + jobs: + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + # This ref does not exist for conflicting PRs + ref: refs/pull/${{ github.event.pull_request.number }}/merge + - language: yaml + label: 'OPTION 1 — use refs/pull/N/head (always exists, no merge applied)' + code: | + jobs: + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + # Always exists — checks out the PR's HEAD commit + ref: refs/pull/${{ github.event.pull_request.number }}/head + - language: yaml + label: 'OPTION 2 — guard: skip merge-ref checkout and fail with a clear message when mergeable is null/false' + code: | + jobs: + test: + runs-on: ubuntu-latest + steps: + - name: Check if PR is mergeable + env: + MERGEABLE: ${{ github.event.pull_request.mergeable }} + run: | + if [ "$MERGEABLE" = "false" ] || [ -z "$MERGEABLE" ]; then + echo "::error::PR has merge conflicts or mergeability not yet computed. Resolve conflicts before CI can test the merged result." + exit 1 + fi + + - uses: actions/checkout@v4 + with: + ref: refs/pull/${{ github.event.pull_request.number }}/merge + - language: yaml + label: 'OPTION 3 — rely on default checkout behavior (uses merge commit when available)' + code: | + jobs: + test: + runs-on: ubuntu-latest + steps: + # Default checkout in pull_request context uses merge commit if mergeable, + # otherwise falls back to the head commit — no manual ref needed + - uses: actions/checkout@v4 +prevention: + - 'Avoid hardcoding refs/pull/N/merge in workflows — use the default checkout or refs/pull/N/head instead' + - 'If you must test the merged result, guard with a mergeability check step first and emit a clear error for conflicting PRs' + - 'Add a required status check that validates PR mergeability so contributors resolve conflicts before CI runs the merge-dependent step' + - 'Note that github.event.pull_request.mergeable can be null (not yet computed) on very recently opened PRs — treat null as non-mergeable' +docs: + - url: 'https://docs.github.com/en/rest/pulls/pulls#get-a-pull-request' + label: 'GitHub REST API: Get a pull request — mergeable and merge_commit_sha fields' + - url: 'https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/events-that-trigger-workflows#pull_request' + label: 'GitHub Docs: pull_request event — checkout behavior' + - url: 'https://github.com/actions/checkout' + label: 'actions/checkout — default ref behavior documentation'