@htekdev/actions-debugger 1.0.113 → 1.0.114

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (25) hide show
  1. package/errors/caching-artifacts/cache-corrupt-on-cancel-during-restore-save-always.yml +136 -0
  2. package/errors/caching-artifacts/restore-keys-asterisk-literal-not-glob.yml +107 -0
  3. package/errors/concurrency-timing/pull-request-review-shared-concurrency-cancels-ci.yml +131 -0
  4. package/errors/known-unsolved/github-script-esm-not-supported.yml +111 -0
  5. package/errors/known-unsolved/job-outputs-string-only-no-array-object.yml +142 -0
  6. package/errors/permissions-auth/oidc-immutable-sub-claim-new-repo-trust-policy-mismatch.yml +122 -0
  7. package/errors/permissions-auth/permissions-auth-064.yml +122 -0
  8. package/errors/permissions-auth/permissions-auth-065.yml +97 -0
  9. package/errors/permissions-auth/permissions-auth-066.yml +129 -0
  10. package/errors/runner-environment/arc-kubernetes-checkout-circular-json-container-hook.yml +101 -0
  11. package/errors/runner-environment/cache-restore-windows-runner-silent-crash.yml +130 -0
  12. package/errors/runner-environment/git-248-fetch-tags-shallow-clone-regression.yml +100 -0
  13. package/errors/runner-environment/javascript-actions-alpine-arm64-not-supported.yml +121 -0
  14. package/errors/runner-environment/runner-environment-188.yml +96 -0
  15. package/errors/runner-environment/runner-environment-191.yml +147 -0
  16. package/errors/runner-environment/runner-environment-192.yml +144 -0
  17. package/errors/runner-environment/runner-environment-193.yml +136 -0
  18. package/errors/runner-environment/runner-environment-194.yml +86 -0
  19. package/errors/silent-failures/checkout-v6-clean-false-deletes-workspace-on-repo-change.yml +119 -0
  20. package/errors/silent-failures/queue-max-silently-ignored-with-cancel-in-progress.yml +109 -0
  21. package/errors/silent-failures/silent-failures-102.yml +141 -0
  22. package/errors/silent-failures/silent-failures-104.yml +119 -0
  23. package/errors/yaml-syntax/yaml-syntax-068.yml +137 -0
  24. package/errors/yaml-syntax/yaml-syntax-069.yml +118 -0
  25. package/package.json +1 -1
@@ -0,0 +1,130 @@
1
+ id: runner-environment-196
2
+ title: 'actions/cache restore silently crashes Windows runner — job jumps to Post cleanup with no error'
3
+ category: runner-environment
4
+ severity: silent-failure
5
+ tags:
6
+ - cache
7
+ - windows
8
+ - crash
9
+ - silent-failure
10
+ - cargo
11
+ - large-cache
12
+ - post-cleanup
13
+ patterns:
14
+ - regex: 'Cache hit for:.*\n(?:.*\n){0,3}Post job cleanup'
15
+ flags: 'i'
16
+ - regex: 'Cache hit for:[\s\S]{0,200}Post job cleanup'
17
+ flags: 'i'
18
+ - regex: 'Cache up-to-date\.\s*\(node:\d+\) \[DEP0040\] DeprecationWarning.*punycode'
19
+ flags: 'i'
20
+ error_messages:
21
+ - 'Cache hit for: [key]'
22
+ - 'Post job cleanup.'
23
+ - 'Cache up-to-date.'
24
+ root_cause: |
25
+ On Windows GitHub-hosted runners, actions/cache@v5 can silently crash the Node.js
26
+ runner process during cache restore when extracting very large cache archives (multi-GB
27
+ caches, e.g. Rust/Cargo registry + cache, large Maven/Gradle dependency trees).
28
+
29
+ The failure manifests as the job jumping directly from "Cache hit for: [key]" to
30
+ "Post job cleanup." with no intervening restore log lines and no error message.
31
+ The step exits with code 0 (success), but the cache was never extracted. Subsequent
32
+ build steps fail with missing dependency errors (e.g. "error: no such file or directory:
33
+ ~/.cargo/registry") rather than a cache-related error, making the root cause opaque.
34
+
35
+ The log sequence for affected runs:
36
+ 1. "Cache hit for: [cache-key]" (restore begins)
37
+ 2. [no tar extraction log lines]
38
+ 3. "Post job cleanup." (job finishes or runner crashes)
39
+ 4. "Cache up-to-date."
40
+ 5. "(node:XXXX) [DEP0040] DeprecationWarning: The `punycode` module is deprecated"
41
+ 6. "Post job cleanup."
42
+
43
+ Root cause analysis: The Windows runner process (Runner.Worker.exe) terminates
44
+ abnormally during tar/zstd decompression of the cache archive. This appears to be a
45
+ memory-related crash (similar to the Windows heap corruption pattern in upload-artifact,
46
+ tracked in toolkit#2406) triggered by the high memory pressure of decompressing large
47
+ archives within the Node.js 20 heap on Windows runners as of May 2026.
48
+
49
+ The crash is non-deterministic (intermittent) — the same cache key may restore
50
+ successfully on retry. Affected cache sizes are typically 1 GB+ uncompressed.
51
+ Rust Cargo caches (registry/index + registry/cache + git/db) are the most commonly
52
+ reported trigger.
53
+
54
+ Source: actions/cache#1754 (May 2026, Windows runner, Cargo cache).
55
+ fix: |
56
+ Short-term workaround: Add `continue-on-error: true` to the cache restore step.
57
+ The job will proceed to the build step which will then reinstall dependencies from
58
+ scratch. The build takes longer but completes reliably.
59
+
60
+ Preferred workaround: Split the cache into smaller chunks. Rust/Cargo caches can be
61
+ split by caching registry/index, registry/cache, and git/db in separate cache steps
62
+ with different keys, keeping each archive under ~500 MB.
63
+
64
+ Alternative: Use sccache or a remote cache (e.g. Cloudflare R2 + sccache) instead of
65
+ actions/cache for Rust builds on Windows — this avoids large local archives entirely.
66
+
67
+ Long-term: Track actions/cache#1754 for an upstream fix. Adding
68
+ `ACTIONS_STEP_DEBUG: true` as a repository secret may reveal the crash signal in
69
+ verbose runner logs.
70
+ fix_code:
71
+ - language: yaml
72
+ label: 'Short-term: continue-on-error to prevent job failure on crash'
73
+ code: |
74
+ - name: Restore Cargo cache
75
+ uses: actions/cache@v5
76
+ continue-on-error: true # Job proceeds even if cache restore crashes
77
+ with:
78
+ path: |
79
+ ~/.cargo/registry/index/
80
+ ~/.cargo/registry/cache/
81
+ ~/.cargo/git/db/
82
+ target/
83
+ key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
84
+ restore-keys: ${{ runner.os }}-cargo-
85
+
86
+ - language: yaml
87
+ label: 'Split large Cargo cache into smaller chunks to avoid crash threshold'
88
+ code: |
89
+ - name: Restore Cargo registry index (small, fast)
90
+ uses: actions/cache@v5
91
+ with:
92
+ path: ~/.cargo/registry/index/
93
+ key: ${{ runner.os }}-cargo-index-${{ hashFiles('**/Cargo.lock') }}
94
+ restore-keys: ${{ runner.os }}-cargo-index-
95
+
96
+ - name: Restore Cargo registry cache (large packages)
97
+ uses: actions/cache@v5
98
+ continue-on-error: true
99
+ with:
100
+ path: ~/.cargo/registry/cache/
101
+ key: ${{ runner.os }}-cargo-cache-${{ hashFiles('**/Cargo.lock') }}
102
+ restore-keys: ${{ runner.os }}-cargo-cache-
103
+
104
+ - name: Restore Cargo git sources
105
+ uses: actions/cache@v5
106
+ continue-on-error: true
107
+ with:
108
+ path: ~/.cargo/git/db/
109
+ key: ${{ runner.os }}-cargo-git-${{ hashFiles('**/Cargo.lock') }}
110
+
111
+ - name: Restore build target dir
112
+ uses: actions/cache@v5
113
+ continue-on-error: true
114
+ with:
115
+ path: target/
116
+ key: ${{ runner.os }}-cargo-target-${{ hashFiles('**/Cargo.lock') }}
117
+
118
+ prevention:
119
+ - 'Keep individual cache archives under ~500 MB by splitting large dependency trees (Cargo, Maven, Gradle) into multiple cache steps'
120
+ - 'Add continue-on-error: true to cache restore steps on Windows runners as a safety net for intermittent crashes'
121
+ - 'Monitor workflow durations — a sudden increase in Windows build time (cache miss equivalent) with no cache-related error in logs is a symptom of this crash'
122
+ - 'For Rust/Cargo on Windows runners, consider sccache with a remote backend to avoid large local cache archives entirely'
123
+ - 'Enable ACTIONS_STEP_DEBUG=true (as repository secret) to capture runner-level crash signals when this failure is suspected'
124
+ docs:
125
+ - url: 'https://github.com/actions/cache/issues/1754'
126
+ label: 'actions/cache#1754 — Windows runner randomly dies during cache restore (May 2026)'
127
+ - url: 'https://github.com/actions/cache#tips-for-using-cache'
128
+ label: 'actions/cache — usage tips and cache size guidance'
129
+ - url: 'https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/caching-dependencies-to-speed-up-workflows'
130
+ label: 'Caching dependencies — limits and best practices'
@@ -0,0 +1,100 @@
1
+ id: runner-environment-190
2
+ title: 'Git 2.48.0 silently stops fetching tags with fetch-tags: true on non-depth-1 shallow clones'
3
+ category: runner-environment
4
+ severity: silent-failure
5
+ tags:
6
+ - git-version
7
+ - fetch-tags
8
+ - shallow-clone
9
+ - fetch-depth
10
+ - ubuntu-24.04
11
+ - regression
12
+ - checkout
13
+ patterns:
14
+ - regex: 'git version 2\.48\.'
15
+ flags: 'i'
16
+ - regex: 'fetch-tags.*fetch-depth|fetch-depth.*fetch-tags'
17
+ flags: 'i'
18
+ error_messages:
19
+ - "# No error — tags are silently absent after checkout with fetch-tags: true and fetch-depth: N on git 2.48.0"
20
+ - "fatal: No names found, cannot describe anything."
21
+ - "fatal: not a tag 'HEAD'"
22
+ root_cause: |
23
+ Git 2.48.0 introduced a change in how `git fetch --depth=N` handles tag following for
24
+ direct refspec fetches. In git ≤ 2.47.x, when actions/checkout ran:
25
+
26
+ git fetch --depth=N origin +<sha>:refs/remotes/origin/<branch>
27
+
28
+ git would automatically follow tags reachable within the depth window — any tag pointing
29
+ to a commit within the fetched depth was included. This is known as automatic tag following.
30
+
31
+ Starting with git 2.48.0, automatic tag following is suppressed for direct refspec fetches
32
+ with `--depth`. Only the explicitly requested ref is fetched; no tags are included even if
33
+ they point to commits within the shallow clone window. The fetch log shows only the branch
34
+ ref fetched — no tag lines appear.
35
+
36
+ Result: `fetch-tags: true` combined with `fetch-depth: N` (where N > 1, such as 100, 383, 500)
37
+ silently returns no tags on runner images shipping git 2.48.0. The workflow log shows no error
38
+ and no warning — `git tag -l` returns empty. Downstream steps using git describe, semantic-release,
39
+ helm chart versioning, or any tool that reads git tags break with "no names found" or
40
+ "not a tag 'HEAD'" errors.
41
+
42
+ This regression first appeared when ubuntu-24.04 runner image updated from 20250105.1.0 to
43
+ 20250113.1.0 (which shipped git 2.48.0). The issue was resolved in runner image 20250117.1.0+
44
+ when git was updated to 2.48.1 which patched the regression. Self-hosted runners running
45
+ git 2.48.0 remain affected.
46
+
47
+ Note: This is distinct from the existing known silent failure where fetch-depth: 1 silently
48
+ fetches no tags regardless of git version. That is expected shallow-clone behavior. This
49
+ regression affects fetch-depth: N > 1 scenarios that previously worked.
50
+ fix: |
51
+ Use `fetch-depth: 0` when git tags are required. A full clone fetches all history and all
52
+ tags regardless of git version. This is the most reliable fix.
53
+
54
+ For large repositories where a full clone is too slow, add a separate fetch --tags step
55
+ immediately after checkout to explicitly fetch all tag objects:
56
+
57
+ git fetch --tags --force
58
+
59
+ Self-hosted runners on git 2.48.0 should upgrade to git 2.48.1 or later which patches
60
+ the tag following regression.
61
+ fix_code:
62
+ - language: yaml
63
+ label: 'Use fetch-depth: 0 for reliable tag fetching (recommended)'
64
+ code: |
65
+ - name: Checkout with full history and all tags
66
+ uses: actions/checkout@v4
67
+ with:
68
+ # fetch-depth: 0 always fetches all commits and tags regardless of git version
69
+ fetch-depth: 0
70
+ - language: yaml
71
+ label: 'Add explicit git fetch --tags step after shallow checkout'
72
+ code: |
73
+ - name: Checkout (shallow)
74
+ uses: actions/checkout@v4
75
+ with:
76
+ fetch-depth: 100
77
+ # fetch-tags: true is unreliable on git 2.48.0 — use explicit fetch instead
78
+
79
+ - name: Fetch tags explicitly (git-version-safe)
80
+ run: git fetch --tags --force
81
+ - language: yaml
82
+ label: 'Check git version in CI for debugging'
83
+ code: |
84
+ - name: Debug git version and tags
85
+ run: |
86
+ git --version
87
+ git tag -l | head -20
88
+ git describe --tags --always || echo "No reachable tags"
89
+ prevention:
90
+ - 'Always use fetch-depth: 0 when git tags are required by downstream steps like git describe or semantic-release'
91
+ - 'Add a git tag -l debug step after checkout to verify tags are present before release tooling runs'
92
+ - 'For self-hosted runners, prefer git 2.48.1+ over 2.48.0 — the regression was patched in 2.48.1'
93
+ - 'Pin to fetch-depth: 0 in release workflows — the performance cost of a full clone is worth the reliability'
94
+ docs:
95
+ - url: 'https://github.com/actions/checkout/issues/2041'
96
+ label: 'actions/checkout#2041: Tags no longer fetch with Git v2.48.0'
97
+ - url: 'https://github.com/actions/checkout#usage'
98
+ label: 'actions/checkout — fetch-depth and fetch-tags input documentation'
99
+ - url: 'https://git-scm.com/docs/git-fetch#_description'
100
+ label: 'git fetch documentation — tag following with --depth'
@@ -0,0 +1,121 @@
1
+ id: runner-environment-195
2
+ title: 'JavaScript Actions in Alpine containers not supported on ARM64 runners'
3
+ category: runner-environment
4
+ severity: error
5
+ tags:
6
+ - alpine
7
+ - arm64
8
+ - javascript-action
9
+ - container
10
+ - ubuntu-24.04-arm
11
+ - musl
12
+ patterns:
13
+ - regex: 'JavaScript Actions in Alpine containers are only supported on x64 Linux runners'
14
+ flags: 'i'
15
+ - regex: 'Detected Linux Arm64'
16
+ flags: 'i'
17
+ - regex: 'JavaScript Actions in Alpine containers.*Detected Linux'
18
+ flags: 'i'
19
+ error_messages:
20
+ - 'Error: JavaScript Actions in Alpine containers are only supported on x64 Linux runners. Detected Linux Arm64'
21
+ root_cause: |
22
+ The Actions runner's container hook for JavaScript-based actions (actions that use
23
+ `using: node20` or `using: node24` in their action.yml) includes a hard platform check
24
+ when the container image is detected as Alpine Linux.
25
+
26
+ Alpine Linux uses musl libc instead of glibc. The Node.js binaries bundled inside
27
+ GitHub-hosted Actions runners are compiled against glibc and cannot run inside Alpine
28
+ containers without compatibility shims. The runner guards against this by rejecting
29
+ JavaScript action execution in Alpine containers that are not on x64 Linux, where a
30
+ limited musl-compatibility workaround exists.
31
+
32
+ On ARM64 runners (ubuntu-24.04-arm, ubuntu-22.04-arm), the runner explicitly rejects
33
+ JavaScript actions run inside Alpine containers with this error. The check evaluates the
34
+ container image's /etc/os-release ID field: when ID=alpine is found AND the runner
35
+ architecture is not x64, the error is thrown.
36
+
37
+ Common trigger patterns:
38
+ - Workflow uses `container: alpine` or a custom image FROM alpine
39
+ - One or more steps use JavaScript-based actions (e.g. actions/upload-artifact,
40
+ actions/checkout, actions/setup-node)
41
+ - Workflow or matrix includes ubuntu-24.04-arm or ubuntu-22.04-arm runners
42
+
43
+ Upgrading to a larger ubuntu-based base image resolves the issue because glibc is
44
+ present. There is no planned fix to add ARM64 Alpine support to the runner.
45
+ fix: |
46
+ Option 1 (recommended): Replace the Alpine container with a Debian/Ubuntu-based image.
47
+ Alpine is often chosen for image size, but if JavaScript actions must be used inside the
48
+ container, a glibc-based image is required on ARM64 runners.
49
+
50
+ Option 2: Run JavaScript actions as host-level steps (outside the container) and
51
+ restrict container use to run: shell steps that do not invoke JS actions.
52
+
53
+ Option 3: Restrict ARM64 runners to non-Alpine container images in your matrix.
54
+
55
+ Option 4: If the Alpine container is only for the build environment, restructure the
56
+ workflow so JavaScript actions (checkout, upload-artifact, etc.) run before the
57
+ container is started rather than inside it.
58
+ fix_code:
59
+ - language: yaml
60
+ label: 'Replace Alpine with Debian-slim (smallest glibc image)'
61
+ code: |
62
+ jobs:
63
+ build:
64
+ runs-on: ubuntu-24.04-arm
65
+ container:
66
+ # Replace: image: alpine:latest
67
+ image: debian:bookworm-slim # glibc-based, JS actions work on ARM64
68
+ steps:
69
+ - uses: actions/checkout@v6
70
+ - run: apt-get update && apt-get install -y curl
71
+ - uses: actions/upload-artifact@v4
72
+ with:
73
+ name: output
74
+ path: dist/
75
+
76
+ - language: yaml
77
+ label: 'Run JS actions on host, only use Alpine container for build steps'
78
+ code: |
79
+ jobs:
80
+ build:
81
+ runs-on: ubuntu-24.04-arm
82
+ steps:
83
+ # Checkout on host (no container) — JS action works fine
84
+ - uses: actions/checkout@v6
85
+ # Run build inside Alpine via docker run (shell step, not JS action)
86
+ - name: Build in Alpine
87
+ run: |
88
+ docker run --rm -v "$GITHUB_WORKSPACE:/work" -w /work \
89
+ alpine:latest sh -c "apk add --no-cache build-base && make"
90
+ # Upload on host — JS action works fine
91
+ - uses: actions/upload-artifact@v4
92
+ with:
93
+ name: output
94
+ path: dist/
95
+
96
+ - language: yaml
97
+ label: 'Matrix: restrict Alpine container to x64 runners only'
98
+ code: |
99
+ jobs:
100
+ build:
101
+ runs-on: ${{ matrix.runner }}
102
+ container:
103
+ image: ${{ matrix.runner == 'ubuntu-24.04-arm' && 'debian:bookworm-slim' || 'alpine:latest' }}
104
+ strategy:
105
+ matrix:
106
+ runner: [ubuntu-24.04, ubuntu-24.04-arm]
107
+ steps:
108
+ - uses: actions/checkout@v6
109
+
110
+ prevention:
111
+ - 'Never use Alpine-based container images on ARM64 GitHub-hosted runners if any workflow step calls a JavaScript action'
112
+ - 'Use debian:bookworm-slim or ubuntu:24.04 as a lightweight glibc alternative to Alpine when JS actions must run in-container on ARM64'
113
+ - 'When migrating workflows to ARM64 runners, audit all container: image values for Alpine derivation (FROM alpine, alpine:latest, alpine:3.x)'
114
+ - 'Run JavaScript actions (checkout, upload-artifact, setup-*) as host-level steps before or after the Alpine container block when possible'
115
+ docs:
116
+ - url: 'https://github.com/actions/upload-artifact/issues/739'
117
+ label: 'actions/upload-artifact#739 — JS Actions in Alpine containers not supported on ARM64 (Feb 2026)'
118
+ - url: 'https://docs.github.com/en/actions/using-github-hosted-runners/using-github-hosted-runners/about-github-hosted-runners#supported-runners-and-hardware-resources'
119
+ label: 'GitHub-hosted runners — ARM64 runner support'
120
+ - url: 'https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/running-jobs-in-a-container'
121
+ label: 'Running jobs in a container'
@@ -0,0 +1,96 @@
1
+ id: runner-environment-188
2
+ title: "macOS Self-Hosted Runner Concurrent Checkout Hangs — git-credential-osxkeychain Deadlock"
3
+ category: runner-environment
4
+ severity: error
5
+ tags:
6
+ - macos
7
+ - self-hosted
8
+ - checkout
9
+ - concurrent
10
+ - osxkeychain
11
+ - credential
12
+ - hang
13
+ patterns:
14
+ - regex: 'git-credential-osxkeychain store'
15
+ flags: i
16
+ - regex: 'run_command.*git-credential-osxkeychain'
17
+ flags: i
18
+ error_messages:
19
+ - "trace: run_command: 'git credential-osxkeychain store'"
20
+ - "trace: exec: git-credential-osxkeychain store"
21
+ - "trace: start_command: /opt/homebrew/opt/git/libexec/git-core/git-credential-osxkeychain store"
22
+ root_cause: |
23
+ When two or more concurrent jobs on the same macOS self-hosted runner both execute
24
+ `actions/checkout`, each job's git process attempts to acquire the macOS Keychain to store
25
+ the authentication token via `git-credential-osxkeychain`. Because the macOS Keychain
26
+ serializes write access, a second concurrent credential store call waits indefinitely for
27
+ the first to release the keychain lock — creating a deadlock that never resolves on its own.
28
+
29
+ The job hangs silently. The last visible log line is always the `git-credential-osxkeychain
30
+ store` trace, followed by no output until the 6-hour GitHub Actions job timeout cancels
31
+ the run. There is no error message — the step simply never completes.
32
+
33
+ Runner v2.331.0 (which moved the base macOS image to 26 / Tahoe) and checkout@v6 together
34
+ worsened the race condition frequency. The issue also affects earlier runner/checkout
35
+ version combinations when multiple jobs share the same macOS self-hosted runner workspace.
36
+ fix: |
37
+ Two workarounds exist. The most reliable is a pre-checkout workspace cleanup step that
38
+ removes leftover lock files from prior concurrent runs. The second is disabling credential
39
+ persistence so git never calls the macOS Keychain at all.
40
+
41
+ Option A (most reliable — workspace cleanup before every checkout):
42
+ Add a step before `actions/checkout` that removes all workspace contents. This eliminates
43
+ stale `.git/index.lock`, `.git/gc.pid` and credential lock files that cause the hang.
44
+
45
+ Option B (simpler — disable credential persistence):
46
+ Set `persist-credentials: false` on the checkout step. This prevents git from calling
47
+ `git-credential-osxkeychain store` entirely since no token is persisted. Note: this
48
+ means subsequent git operations in the same job cannot use the persisted token, so you
49
+ must pass the token explicitly in each git call that needs it.
50
+
51
+ If the workspace directory itself is the issue (leftover `.git/index.lock`), add an explicit
52
+ pre-step that deletes `.git/index.lock` and `.git/gc.pid` if they exist.
53
+ fix_code:
54
+ - language: yaml
55
+ label: "Option A — pre-checkout workspace cleanup (most reliable)"
56
+ code: |
57
+ jobs:
58
+ build:
59
+ runs-on: [self-hosted, macos]
60
+ steps:
61
+ - name: Clean workspace before checkout
62
+ run: |
63
+ find "$GITHUB_WORKSPACE" -mindepth 1 -maxdepth 1 -exec rm -rf {} + \
64
+ || echo "::warning::Workspace cleanup failed due to concurrent writes. Not fatal."
65
+ - uses: actions/checkout@v6
66
+ - language: yaml
67
+ label: "Option B — disable credential persistence to skip keychain"
68
+ code: |
69
+ jobs:
70
+ build:
71
+ runs-on: [self-hosted, macos]
72
+ steps:
73
+ - uses: actions/checkout@v6
74
+ with:
75
+ persist-credentials: false
76
+ - language: yaml
77
+ label: "Delete stale git lock files before checkout"
78
+ code: |
79
+ - name: Remove stale git lock files
80
+ run: |
81
+ rm -f "$GITHUB_WORKSPACE/.git/index.lock"
82
+ rm -f "$GITHUB_WORKSPACE/.git/gc.pid"
83
+ - uses: actions/checkout@v6
84
+ prevention:
85
+ - "Use ephemeral self-hosted macOS runners (each job gets a fresh runner) to eliminate workspace state sharing between concurrent jobs"
86
+ - "Limit concurrency on the macOS runner's job queue to 1 using a concurrency group if ephemeral runners are not available"
87
+ - "Add a pre-checkout workspace cleanup step as a defensive measure on all macOS self-hosted runner jobs"
88
+ - "Set `persist-credentials: false` if downstream git operations do not require the persisted token"
89
+ - "Upgrade to the latest actions/checkout — version tags and runner versions interact; newer releases may reduce the deadlock window"
90
+ docs:
91
+ - url: "https://stackoverflow.com/questions/79881327/github-actions-self-hosted-runner-on-macos-tries-to-checkout-repository-forever"
92
+ label: "Stack Overflow — macOS self-hosted runner checkout hangs forever (Feb 2026)"
93
+ - url: "https://github.com/actions/checkout/issues/550"
94
+ label: "actions/checkout#550 — Checkout gets stuck forever randomly on self-hosted runners"
95
+ - url: "https://docs.github.com/en/actions/hosting-your-own-runners/managing-self-hosted-runners/about-self-hosted-runners"
96
+ label: "GitHub Docs: About self-hosted runners"
@@ -0,0 +1,147 @@
1
+ id: runner-environment-191
2
+ title: 'GHCup 0.1.x → 0.2.x Upgrade on Ubuntu Runners Breaks Direct ghcup CLI Usage'
3
+ category: runner-environment
4
+ severity: error
5
+ tags:
6
+ - haskell
7
+ - ghcup
8
+ - ubuntu-22.04
9
+ - ubuntu-24.04
10
+ - runner-image
11
+ - breaking-change
12
+ patterns:
13
+ - regex: 'ghcup: command not found'
14
+ flags: 'i'
15
+ - regex: 'ghcup list.*-r[0-9]+|version.*-r[0-9].*not found'
16
+ flags: 'i'
17
+ - regex: '\$HOME/\.ghcup/bin/ghc.*no such file|\.ghcup/bin/ghc.*not a regular file'
18
+ flags: 'i'
19
+ - regex: 'ghcup.*cabal install.*unknown command|cabal install.*unrecognized.*ghcup'
20
+ flags: 'i'
21
+ error_messages:
22
+ - 'test -f ~/.ghcup/bin/ghc returned false (ghc not installed)'
23
+ - 'GHC version 9.6.6-r1 was not found in the expected location'
24
+ - 'Error: The value 9.6.6-r1 is not a valid GHC version'
25
+ - 'ghcup: error: no subcommand: cabal install'
26
+ root_cause: |
27
+ The ubuntu-22.04 and ubuntu-24.04 runner image update released 2026-05-26
28
+ (ubuntu24/20260525.161.1, ubuntu22/20260525.156.1) upgraded the pre-installed GHCup
29
+ from 0.1.50.2 to 0.2.5.0. GHCup 0.2.x introduced several breaking CLI and
30
+ filesystem changes that affect workflows calling ghcup directly.
31
+
32
+ **Breaking changes in GHCup 0.2.x:**
33
+
34
+ 1. **`ghcup list` version strings now include a `-rX` revision suffix** when a
35
+ revision update is available (e.g., `9.6.6-r1` instead of `9.6.6`). Scripts
36
+ that parse `ghcup list` output for version equality checks (e.g., `grep 9.6.6`)
37
+ or that pipe the version into other tools fail because of the unexpected suffix.
38
+
39
+ 2. **`~/.ghcup/bin/` is now entirely composed of symlinks** (except the `ghcup`
40
+ binary itself). Previously, some binaries (like `ghc`, `cabal`, `hls`) were
41
+ hardlinks or regular executable files. Workflow steps using the POSIX file-
42
+ existence test `-f ~/.ghcup/bin/ghc` now return false because `-f` returns
43
+ false for symlinks. The check must be `-e` (exists) or `-L` (is symlink).
44
+
45
+ 3. **Old undocumented subcommand alias removed**: `ghcup cabal install <ver>` as
46
+ an alternative form is gone. The canonical form `ghcup install cabal <ver>` and
47
+ `ghcup install ghc <ver>` still work. Workflows that copied old forum examples
48
+ using the deprecated form receive an "unknown subcommand" error.
49
+
50
+ 4. **`ghcup compile hls --isolate=<dir>` changed output path**: binaries are now
51
+ installed into `<dir>/bin/` instead of `<dir>/`. Scripts expecting the binary
52
+ directly at the isolate path fail with "file not found".
53
+
54
+ Note: The `--install-targets` flag bug present in GHCup 0.2.0–0.2.2 was already
55
+ fixed before the runner images updated (runner ships 0.2.5.0). That specific bug
56
+ does not affect GitHub-hosted runners.
57
+ fix: |
58
+ **For `-f` file existence checks** — replace with `-e` (any file type) or
59
+ `-L` (is symlink):
60
+
61
+ ```bash
62
+ # Before (breaks on GHCup 0.2.x):
63
+ if [ -f "$HOME/.ghcup/bin/ghc" ]; then ...
64
+
65
+ # After:
66
+ if [ -e "$HOME/.ghcup/bin/ghc" ]; then ...
67
+ ```
68
+
69
+ **For version parsing from `ghcup list`** — strip the revision suffix:
70
+
71
+ ```bash
72
+ GHC_VER=$(ghcup list -t ghc --show-criteria 'recommended' -r | awk '{print $2}' \
73
+ | sed 's/-r[0-9]*$//')
74
+ ```
75
+
76
+ Or use `--show-revisions=none` to suppress the suffix entirely:
77
+
78
+ ```bash
79
+ ghcup list -t ghc --show-revisions=none
80
+ ```
81
+
82
+ **For old subcommand syntax** — use the canonical form:
83
+
84
+ ```bash
85
+ # Before:
86
+ ghcup cabal install 3.12.1.0
87
+
88
+ # After:
89
+ ghcup install cabal 3.12.1.0
90
+ ```
91
+
92
+ **Best practice** — use `haskell-actions/setup` instead of calling ghcup
93
+ directly. The action is maintained to handle ghcup version changes:
94
+
95
+ ```yaml
96
+ - uses: haskell-actions/setup@v2
97
+ with:
98
+ ghc-version: '9.6.6'
99
+ cabal-version: 'latest'
100
+ ```
101
+ fix_code:
102
+ - language: yaml
103
+ label: 'Use haskell-actions/setup instead of raw ghcup commands'
104
+ code: |
105
+ - name: Set up GHC
106
+ uses: haskell-actions/setup@v2
107
+ with:
108
+ ghc-version: '9.6.6'
109
+ cabal-version: 'latest'
110
+ enable-stack: false
111
+
112
+ - language: yaml
113
+ label: 'Conditional GHCup binary check — fix -f to -e'
114
+ code: |
115
+ - name: Check if GHC is available
116
+ run: |
117
+ # GHCup 0.2.x: all ~/.ghcup/bin/ entries are symlinks; use -e not -f
118
+ if [ -e "$HOME/.ghcup/bin/ghc" ]; then
119
+ echo "GHC found: $(ghc --version)"
120
+ else
121
+ ghcup install ghc recommended
122
+ fi
123
+
124
+ - language: yaml
125
+ label: 'Parse GHCup list output — strip revision suffix'
126
+ code: |
127
+ - name: Get recommended GHC version
128
+ run: |
129
+ # GHCup 0.2.x: version may include -rX revision suffix
130
+ GHC_VER=$(ghcup list -t ghc --show-revisions=none -r \
131
+ | grep 'recommended' | awk '{print $2}')
132
+ echo "GHC version: $GHC_VER"
133
+ ghcup install ghc "$GHC_VER"
134
+ prevention:
135
+ - 'Use haskell-actions/setup instead of calling ghcup directly — it handles ghcup API changes across versions.'
136
+ - 'Use `-e` or `-L` for file existence checks on `~/.ghcup/bin/` entries, never `-f`.'
137
+ - 'Pin to specific GHC/Cabal versions in haskell-actions/setup rather than resolving "recommended" at runtime.'
138
+ - 'When parsing `ghcup list` output, use `--show-revisions=none` to suppress the `-rX` suffix added in 0.2.x.'
139
+ docs:
140
+ - url: 'https://github.com/haskell/ghcup-hs/releases/tag/v0.2.1.0'
141
+ label: 'GHCup 0.2.1.0 release notes (breaking changes section)'
142
+ - url: 'https://github.com/actions/runner-images/releases/tag/ubuntu24%2F20260525.161'
143
+ label: 'Ubuntu 24.04 runner image release 20260525.161.1 — GHCup 0.1.50.2 → 0.2.5.0'
144
+ - url: 'https://github.com/actions/runner-images/issues/14142'
145
+ label: 'runner-images #14142 — GHCup 0.2 version banner format change'
146
+ - url: 'https://github.com/haskell/haskell-actions/tree/main/setup'
147
+ label: 'haskell-actions/setup — official Haskell CI setup action'