Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
127 changes: 127 additions & 0 deletions errors/caching-artifacts/ca-146.yml
Original file line number Diff line number Diff line change
@@ -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'
124 changes: 124 additions & 0 deletions errors/caching-artifacts/ca-147.yml
Original file line number Diff line number Diff line change
@@ -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 <sha>. 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'
130 changes: 130 additions & 0 deletions errors/runner-environment/re-489.yml
Original file line number Diff line number Diff line change
@@ -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'
Loading