@htekdev/actions-debugger 1.0.2 → 1.0.3

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.
@@ -0,0 +1,118 @@
1
+ id: caching-artifacts-010
2
+ title: "Artifact Download Fails — Unable to Find Any Artifacts for Run"
3
+ category: caching-artifacts
4
+ severity: error
5
+ tags:
6
+ - artifact
7
+ - download
8
+ - run-id
9
+ - cross-workflow
10
+ - upload-artifact
11
+ - download-artifact
12
+ patterns:
13
+ - regex: "Unable to find any artifacts for the associated workflow"
14
+ flags: "i"
15
+ - regex: "No artifacts found for run"
16
+ flags: "i"
17
+ - regex: "Error: Unable to find any artifacts"
18
+ flags: "i"
19
+ error_messages:
20
+ - "Unable to find any artifacts for the associated workflow"
21
+ - "Error: Unable to find any artifacts for the associated workflow"
22
+ - "No artifacts were found with the provided name and filters."
23
+ root_cause: |
24
+ GitHub Actions artifacts are scoped to a specific workflow run. The
25
+ `actions/download-artifact@v4` action (and v3 with `run-id:`) will fail with
26
+ "Unable to find any artifacts" when:
27
+
28
+ 1. **Wrong or stale run-id** — The run ID is hard-coded or fetched from a
29
+ prior run that no longer has the expected artifact (artifacts expire after
30
+ the configured retention period, default 90 days).
31
+
32
+ 2. **Upload step never ran** — The producing workflow job was cancelled, the
33
+ upload step was skipped due to a failed prior step, or the `if:` condition
34
+ on the upload step evaluated to false.
35
+
36
+ 3. **Name mismatch** — The `name:` specified in `download-artifact` doesn't
37
+ exactly match the name used in `upload-artifact` (case-sensitive).
38
+
39
+ 4. **Cross-workflow download without explicit run-id** — In v4, downloading
40
+ artifacts from a different workflow run requires an explicit `run-id:`.
41
+ Omitting it defaults to the current run, which may not have those artifacts.
42
+
43
+ Documented in GitHub Community discussion #109905.
44
+ fix: |
45
+ For cross-workflow artifact sharing:
46
+ 1. Capture the producing workflow's run-id dynamically using the GitHub REST
47
+ API or by passing it as a workflow_dispatch input or repository_dispatch payload.
48
+ 2. Verify the upload step ran successfully in the producer workflow before
49
+ downloading in a consumer workflow.
50
+ 3. Ensure `name:` matches exactly (case-sensitive) between upload and download.
51
+ 4. For same-workflow jobs, omit `run-id:` — download-artifact v4 defaults to
52
+ the current run automatically.
53
+ fix_code:
54
+ - language: yaml
55
+ label: "WRONG — hard-coded run-id that may be stale"
56
+ code: |
57
+ - uses: actions/download-artifact@v4
58
+ with:
59
+ name: build-output
60
+ run-id: 12345678 # ❌ hard-coded run ID — stale if re-run or wrong workflow
61
+ - language: yaml
62
+ label: "RIGHT — same-workflow, no run-id needed"
63
+ code: |
64
+ # Job A (producer)
65
+ jobs:
66
+ build:
67
+ runs-on: ubuntu-latest
68
+ steps:
69
+ - run: make build
70
+ - uses: actions/upload-artifact@v4
71
+ with:
72
+ name: build-output # ✅ exact name matters
73
+ path: dist/
74
+
75
+ test:
76
+ needs: build
77
+ runs-on: ubuntu-latest
78
+ steps:
79
+ - uses: actions/download-artifact@v4
80
+ with:
81
+ name: build-output # ✅ same name, no run-id needed for current run
82
+ - language: yaml
83
+ label: "RIGHT — cross-workflow download, run-id from API"
84
+ code: |
85
+ - name: Get latest successful run ID
86
+ id: get-run
87
+ env:
88
+ GH_TOKEN: ${{ github.token }}
89
+ run: |
90
+ RUN_ID=$(gh run list \
91
+ --workflow=build.yml \
92
+ --branch=main \
93
+ --status=success \
94
+ --limit=1 \
95
+ --json databaseId \
96
+ --jq '.[0].databaseId')
97
+ echo "run_id=$RUN_ID" >> $GITHUB_OUTPUT
98
+
99
+ - uses: actions/download-artifact@v4
100
+ with:
101
+ name: build-output
102
+ run-id: ${{ steps.get-run.outputs.run_id }} # ✅ dynamic run ID
103
+ github-token: ${{ github.token }}
104
+ prevention:
105
+ - "Never hard-code run-id values — always fetch them dynamically via the GitHub API or pass them as workflow inputs."
106
+ - "Always verify artifact upload completed successfully before writing a consuming workflow that depends on it."
107
+ - "Use exact case-matching artifact names — `build-output` and `Build-Output` are different artifacts."
108
+ - "For same-workflow artifact sharing between jobs, omit `run-id:` entirely — it defaults to the current run."
109
+ - "Check artifact retention settings — artifacts expire after 90 days (public) or 400 days (private) by default."
110
+ docs:
111
+ - url: "https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/storing-and-sharing-data-from-a-workflow"
112
+ label: "Storing and sharing data from a workflow"
113
+ - url: "https://github.com/actions/download-artifact"
114
+ label: "actions/download-artifact — README and cross-run download docs"
115
+ - url: "https://github.com/orgs/community/discussions/109905"
116
+ label: "GitHub Community #109905 — Unable to find any artifacts troubleshooting"
117
+ - url: "https://stackoverflow.com/questions/78238187/unable-to-find-any-artifacts-for-the-associated-workflow-github-actions"
118
+ label: "Stack Overflow — Unable to find any artifacts for the associated workflow"
@@ -0,0 +1,89 @@
1
+ id: runner-environment-018
2
+ title: "macOS 14 Sonoma Runner Deprecation — EOL November 2026"
3
+ category: runner-environment
4
+ severity: warning
5
+ tags:
6
+ - macos
7
+ - deprecation
8
+ - runner-image
9
+ - eol
10
+ - migration
11
+ patterns:
12
+ - regex: "##\\[error\\]This request was rejected because.*macos-14"
13
+ flags: "i"
14
+ - regex: "Image.*macos-14.*deprecated|macos-14.*no longer supported"
15
+ flags: "i"
16
+ - regex: "The requested image.*macos-14.*not available"
17
+ flags: "i"
18
+ error_messages:
19
+ - "##[error]This request was rejected because the runner label 'macos-14' is no longer supported."
20
+ - "The macOS 14 image has been retired. Please update to macos-15 or macos-latest."
21
+ root_cause: |
22
+ GitHub announced the deprecation of `macOS 14 Sonoma` runner images on the following schedule:
23
+ - **Deprecation begins**: July 6, 2026 — longer queue times during peak hours, brownout periods
24
+ - **Full retirement**: November 2, 2026 — jobs using `macos-14` will fail permanently
25
+
26
+ GitHub maintains only the latest two stable macOS major versions. Since macOS 26 Tahoe is now
27
+ GA on GitHub Actions, macOS 14 is the oldest and must retire.
28
+
29
+ **Brownout schedule** (jobs deliberately failed during these windows to force migration):
30
+ - October 5, 14:00 UTC – October 6, 00:00 UTC
31
+ - October 12, 14:00 UTC – October 13, 00:00 UTC
32
+ - October 16–30, 14:00 UTC – next day 00:00 UTC (escalating weekly)
33
+
34
+ Affected labels: `macos-14`, `macos-14-large`, `macos-14-xlarge`.
35
+ fix: |
36
+ Update your workflow's `runs-on` label to a supported macOS version:
37
+
38
+ | Old label | Replace with |
39
+ |-----------|--------------|
40
+ | `macos-14` | `macos-latest` or `macos-15` or `macos-26` |
41
+ | `macos-14-large` | `macos-latest-large` or `macos-15-large` |
42
+ | `macos-14-xlarge` | `macos-latest-xlarge` or `macos-15-xlarge` or `macos-26-xlarge` |
43
+
44
+ If your workflow depends on macOS 14-specific software versions (e.g., Xcode 15, older
45
+ Python/Ruby), test carefully against macOS 15 before switching `macos-latest`.
46
+ See runner-environment-017 for macOS 15 → 26 migration notes if moving to `macos-latest`.
47
+ fix_code:
48
+ - language: yaml
49
+ label: "Migrate from macos-14 to macos-15 (conservative) or macos-latest"
50
+ code: |
51
+ jobs:
52
+ build:
53
+ # Before:
54
+ # runs-on: macos-14
55
+
56
+ # Conservative: macos-15 (similar software stack, no OpenSSL jump)
57
+ runs-on: macos-15
58
+
59
+ # OR accept latest (currently macos-26 after June 15 2026):
60
+ # runs-on: macos-latest
61
+
62
+ steps:
63
+ - uses: actions/checkout@v4
64
+ - language: yaml
65
+ label: "Strategy matrix: test across multiple macOS versions during migration"
66
+ code: |
67
+ jobs:
68
+ build:
69
+ strategy:
70
+ matrix:
71
+ os: [macos-15, macos-26]
72
+ runs-on: ${{ matrix.os }}
73
+ steps:
74
+ - uses: actions/checkout@v4
75
+ - name: Build and test
76
+ run: make test
77
+ prevention:
78
+ - "Subscribe to actions/runner-images GitHub Issues announcements label to receive deprecation notices well in advance."
79
+ - "Avoid pinning to specific macOS point versions (`macos-14`, `macos-15`) in long-lived workflows — use `macos-latest` and test proactively against the next version."
80
+ - "Run a matrix strategy against `macos-latest` and your pinned version to detect incompatibilities before they cause production failures."
81
+ - "Search your organization's workflows periodically for deprecated runner labels using: `gh search code 'runs-on: macos-14' --owner YOUR_ORG`."
82
+ docs:
83
+ - url: "https://github.com/actions/runner-images/issues/13518"
84
+ label: "GitHub Announcement: macOS 14 Sonoma deprecation timeline"
85
+ - url: "https://docs.github.com/en/actions/using-github-hosted-runners/using-github-hosted-runners/about-github-hosted-runners#supported-runners-and-hardware-resources"
86
+ label: "Supported GitHub-hosted runner labels"
87
+ source:
88
+ article: "https://htek.dev/articles/github-actions-debugging-guide"
89
+ section: "Runner deprecation and EOL"
@@ -0,0 +1,127 @@
1
+ id: runner-environment-017
2
+ title: "macos-latest Label Now Points to macOS 26 Tahoe"
3
+ category: runner-environment
4
+ severity: error
5
+ tags:
6
+ - macos
7
+ - runner-image
8
+ - breaking-change
9
+ - openssl
10
+ - xcode
11
+ - migration
12
+ patterns:
13
+ - regex: "Error opening configuration file.*openssl"
14
+ flags: "i"
15
+ - regex: "SSL_CTX_new.*failed|SSL_connect.*SYSCALL error"
16
+ flags: "i"
17
+ - regex: "Could not find Xcode.*version.*16\\.\\d"
18
+ flags: "i"
19
+ - regex: "ruby.*requires.*Ruby (2|3\\.0|3\\.1|3\\.2|3\\.3)"
20
+ flags: "i"
21
+ - regex: "dyld.*Library not loaded.*libssl\\.1\\.1"
22
+ flags: "i"
23
+ error_messages:
24
+ - "dyld[]: Library not loaded: /usr/local/opt/openssl@1.1/lib/libssl.1.1.dylib"
25
+ - "Could not find Xcode version '16.4'"
26
+ - "SSL_connect returned=1 errno=0 state=error: certificate verify failed"
27
+ - "Your Ruby version is 3.3.x, but your Gemfile specified ~> 3.3"
28
+ - "npm warn old lockfile"
29
+ root_cause: |
30
+ The `macos-latest` label in GitHub Actions was migrated to point to macOS 26 Tahoe
31
+ beginning June 15, 2026 (completing by July 15, 2026). Previously it pointed to macOS 15
32
+ Sequoia. This migration includes several major software version changes that silently break
33
+ workflows:
34
+
35
+ - **OpenSSL**: 1.1.1w → 3.6.2 — The biggest breaking change. Many C/C++ projects,
36
+ Ruby gems (openssl), and Python packages that link against the system OpenSSL dynamically
37
+ will fail at runtime because libssl.1.1.dylib no longer ships with macOS 26.
38
+ - **Xcode**: Default changes from 16.4 to 26.4.1 (Xcode 26 series). Workflows pinning
39
+ `xcode-version: '16.4'` or relying on Clang 17 will break — Clang/LLVM jumps from 17 → 21.
40
+ - **Ruby**: 3.3.x → 3.4.x — Minor version bump can cause Gemfile constraint failures and
41
+ gem native extension compilation issues.
42
+ - **Node.js**: Default moves from 22 → 24 (though both images include Node 24 in cached tools).
43
+ - **npm**: 10.x → 11.x — Major npm version. Package-lock.json format changes possible.
44
+ - **Homebrew LLVM**: 18 → 20 (major version jump for workflows using `llvm@18` explicitly).
45
+ fix: |
46
+ **Immediate mitigation:** Pin to `macos-15` to restore previous behavior while you migrate:
47
+
48
+ ```yaml
49
+ runs-on: macos-15
50
+ ```
51
+
52
+ **Proper fix** — address each breaking dependency:
53
+
54
+ 1. **OpenSSL**: Brew-install a pinned OpenSSL version and set library paths:
55
+ ```bash
56
+ brew install openssl@1.1
57
+ export LDFLAGS="-L$(brew --prefix openssl@1.1)/lib"
58
+ export CPPFLAGS="-I$(brew --prefix openssl@1.1)/include"
59
+ ```
60
+ Or migrate to OpenSSL 3.x compatible code.
61
+
62
+ 2. **Xcode**: Pin the Xcode version explicitly using `maxim-lobanov/setup-xcode`:
63
+ ```yaml
64
+ - uses: maxim-lobanov/setup-xcode@v1
65
+ with:
66
+ xcode-version: '16.4'
67
+ ```
68
+ Or migrate your project to Xcode 26.
69
+
70
+ 3. **Ruby**: Update your Gemfile to accept 3.4.x (`~> 3.4`) or use `ruby/setup-ruby` to
71
+ pin a specific version:
72
+ ```yaml
73
+ - uses: ruby/setup-ruby@v1
74
+ with:
75
+ ruby-version: '3.3'
76
+ ```
77
+ fix_code:
78
+ - language: yaml
79
+ label: "Pin to macos-15 for immediate rollback"
80
+ code: |
81
+ jobs:
82
+ build:
83
+ runs-on: macos-15 # pinned until macos-26 migration complete
84
+ steps:
85
+ - uses: actions/checkout@v4
86
+ - language: yaml
87
+ label: "Full macos-26 compatible workflow — pin Xcode, Ruby, and OpenSSL"
88
+ code: |
89
+ jobs:
90
+ build:
91
+ runs-on: macos-latest # now macos-26
92
+ steps:
93
+ - uses: actions/checkout@v4
94
+
95
+ # Pin Xcode version explicitly
96
+ - uses: maxim-lobanov/setup-xcode@v1
97
+ with:
98
+ xcode-version: '26.4'
99
+
100
+ # Pin Ruby if needed
101
+ - uses: ruby/setup-ruby@v1
102
+ with:
103
+ ruby-version: '3.3'
104
+ bundler-cache: true
105
+
106
+ # If OpenSSL 1.1 is needed, install and export paths
107
+ - name: Install OpenSSL 1.1
108
+ run: |
109
+ brew install openssl@1.1
110
+ echo "LDFLAGS=-L$(brew --prefix openssl@1.1)/lib" >> $GITHUB_ENV
111
+ echo "CPPFLAGS=-I$(brew --prefix openssl@1.1)/include" >> $GITHUB_ENV
112
+ prevention:
113
+ - "Avoid relying on `macos-latest` for builds that depend on specific system library versions (OpenSSL, LLVM). Pin to a concrete label like `macos-15`."
114
+ - "Subscribe to the actions/runner-images repository announcements to get advance notice of `macos-latest` label migrations."
115
+ - "Use `ruby/setup-ruby`, `actions/setup-node`, and `actions/setup-python` to pin language runtimes instead of relying on runner image defaults."
116
+ - "Test your macOS workflows against the new image early by substituting `macos-26` before the `macos-latest` migration completes."
117
+ - "Audit all dylib/framework dependencies — anything linking to libssl.1.1 must be migrated to OpenSSL 3.x or brew-pinned."
118
+ docs:
119
+ - url: "https://github.com/actions/runner-images/issues/14167"
120
+ label: "GitHub Announcement: macos-latest will use macos-26 in June 2026"
121
+ - url: "https://github.com/actions/runner-images/blob/main/images/macos/macos-26-arm64-Readme.md"
122
+ label: "macOS 26 arm64 image README — full software list"
123
+ - url: "https://docs.github.com/en/actions/using-github-hosted-runners/using-github-hosted-runners/about-github-hosted-runners"
124
+ label: "About GitHub-hosted runners — supported runner labels"
125
+ source:
126
+ article: "https://htek.dev/articles/github-actions-debugging-guide"
127
+ section: "Runner image migrations"
@@ -0,0 +1,112 @@
1
+ id: runner-environment-019
2
+ title: "PowerShell 7.4 → 7.6 LTS Upgrade Breaks pwsh Scripts"
3
+ category: runner-environment
4
+ severity: warning
5
+ tags:
6
+ - powershell
7
+ - pwsh
8
+ - runner-image
9
+ - breaking-change
10
+ - windows
11
+ - linux
12
+ patterns:
13
+ - regex: "The term 'ThreadJob\\\\\\\\Start-ThreadJob' is not recognized"
14
+ flags: "i"
15
+ - regex: "Cannot bind parameter.*ChildPath.*expected.*String.*got.*Array"
16
+ flags: "i"
17
+ - regex: "WildcardPattern.*backtick|escape.*pattern.*unexpected"
18
+ flags: "i"
19
+ - regex: "New-EventLog.*source.*trailing|event source.*not found"
20
+ flags: "i"
21
+ error_messages:
22
+ - "The term 'ThreadJob\\Start-ThreadJob' is not recognized as a name of a cmdlet, function, script file, or executable program."
23
+ - "Cannot bind parameter 'ChildPath'. Cannot convert the 'System.Object[]' value of type 'System.Object[]' to type 'System.String'."
24
+ - "Start-ThreadJob : The term 'ThreadJob\\Start-ThreadJob' is not recognized"
25
+ root_cause: |
26
+ GitHub Actions upgraded PowerShell from 7.4.x to 7.6 LTS on all runner images beginning
27
+ June 8, 2026 (completing June 15, 2026). This affects every runner OS: ubuntu-22.04,
28
+ ubuntu-24.04, ubuntu-slim, macos-14/15/26, windows-2022/2025/2025-vs2026.
29
+
30
+ PowerShell 7.6 is built on .NET 10 (7.4 was on .NET 8). The documented breaking changes are:
31
+
32
+ 1. **ThreadJob module renamed**: `ThreadJob` module is now `Microsoft.PowerShell.ThreadJob`.
33
+ Scripts calling `ThreadJob\Start-ThreadJob` with the old module-qualified name will throw
34
+ a "not recognized" error. The cmdlet itself (`Start-ThreadJob`) still works without prefix.
35
+
36
+ 2. **`Join-Path -ChildPath` now accepts `string[]`**: Parameter binding changed from `string`
37
+ to `string[]`. Existing code that passes multiple -ChildPath args may see binding errors
38
+ depending on how arguments were constructed.
39
+
40
+ 3. **`WildcardPattern.Escape` now correctly escapes lone backticks**: Scripts that relied on
41
+ the previous (incorrect) behavior of backtick handling in wildcard patterns may produce
42
+ different results.
43
+
44
+ 4. **Event source name trailing space removed**: New-EventLog / Write-EventLog source names
45
+ no longer have a trailing space. Scripts that matched exact event source names including
46
+ the trailing space (e.g., `"MySource "`) will fail to match.
47
+
48
+ 5. **.NET 10 runtime**: Any `pwsh` script using .NET types or reflection that was tested
49
+ against .NET 8 behavior may see subtle differences.
50
+ fix: |
51
+ **ThreadJob module name** — the most common breaking change:
52
+ Replace `ThreadJob\Start-ThreadJob` with `Microsoft.PowerShell.ThreadJob\Start-ThreadJob`,
53
+ or just call `Start-ThreadJob` without the module qualifier.
54
+
55
+ **Event source name** — if you match exact source names:
56
+ Trim any trailing spaces from source name comparisons.
57
+
58
+ **Pin PowerShell version** if you need time to migrate (not recommended long-term):
59
+ Install a specific pwsh version in your workflow before running scripts.
60
+
61
+ **Test locally**: Install PowerShell 7.6 (`winget install Microsoft.PowerShell`) and run
62
+ your scripts to catch any remaining issues before they surface in CI.
63
+ fix_code:
64
+ - language: yaml
65
+ label: "Fix ThreadJob module-qualified name"
66
+ code: |
67
+ # In your PowerShell script — change this:
68
+ # ThreadJob\Start-ThreadJob -ScriptBlock { ... }
69
+ # To either:
70
+ # Start-ThreadJob -ScriptBlock { ... } # simplest fix
71
+ # Microsoft.PowerShell.ThreadJob\Start-ThreadJob -ScriptBlock { ... } # fully qualified
72
+ - language: yaml
73
+ label: "Pin PowerShell version as a temporary workaround"
74
+ code: |
75
+ jobs:
76
+ build:
77
+ runs-on: ubuntu-latest
78
+ steps:
79
+ - uses: actions/checkout@v4
80
+
81
+ # Pin pwsh to 7.4.x temporarily while migrating
82
+ - name: Install PowerShell 7.4
83
+ run: |
84
+ wget -q "https://github.com/PowerShell/PowerShell/releases/download/v7.4.10/powershell_7.4.10-1.deb_amd64.deb"
85
+ sudo dpkg -i powershell_7.4.10-1.deb_amd64.deb
86
+
87
+ - name: Run PowerShell script
88
+ shell: pwsh
89
+ run: ./scripts/build.ps1
90
+ - language: yaml
91
+ label: "Fix event source name trailing-space match"
92
+ code: |
93
+ # Before (broken on 7.6):
94
+ # if ($event.Source -eq "MyApp ") { ... }
95
+ #
96
+ # After (works on 7.4 and 7.6):
97
+ # if ($event.Source.Trim() -eq "MyApp") { ... }
98
+ prevention:
99
+ - "Subscribe to actions/runner-images announcements for PowerShell upgrade notices well before they ship."
100
+ - "Always use unqualified cmdlet names (`Start-ThreadJob`) rather than module-qualified names (`ThreadJob\\Start-ThreadJob`) to avoid module-rename breakage."
101
+ - "Run your PowerShell scripts through PSScriptAnalyzer with the latest rule set after any PS version upgrade."
102
+ - "Test pwsh workflows in a matrix with the previous and new PS version during runner image transition periods."
103
+ docs:
104
+ - url: "https://github.com/actions/runner-images/issues/14150"
105
+ label: "GitHub Announcement: PowerShell 7.4 → 7.6 upgrade on all runner images"
106
+ - url: "https://learn.microsoft.com/en-us/powershell/scripting/whats-new/what-s-new-in-powershell-76"
107
+ label: "PowerShell 7.6 release notes and breaking changes"
108
+ - url: "https://learn.microsoft.com/en-us/powershell/scripting/install/powershell-support-lifecycle"
109
+ label: "PowerShell support lifecycle"
110
+ source:
111
+ article: "https://htek.dev/articles/github-actions-debugging-guide"
112
+ section: "Runner image tool version changes"
@@ -0,0 +1,126 @@
1
+ id: runner-environment-021
2
+ title: "Service Container Marked Unhealthy — Health Check Timeout"
3
+ category: runner-environment
4
+ severity: error
5
+ tags:
6
+ - service-container
7
+ - healthcheck
8
+ - docker
9
+ - timeout
10
+ - postgres
11
+ - redis
12
+ - rabbitmq
13
+ patterns:
14
+ - regex: "service is unhealthy"
15
+ flags: "i"
16
+ - regex: "Failed to initialize.*service is unhealthy"
17
+ flags: "i"
18
+ - regex: "##\\[error\\]Failed to initialize.*service"
19
+ flags: "i"
20
+ - regex: "container_id.*unhealthy"
21
+ flags: "i"
22
+ error_messages:
23
+ - "##[error]Failed to initialize, rabbitmq service is unhealthy."
24
+ - "##[error]Failed to initialize, postgres service is unhealthy."
25
+ - "##[error]Failed to initialize, redis service is unhealthy."
26
+ - "unhealthy"
27
+ - "service is starting, waiting 29 seconds before checking again."
28
+ root_cause: |
29
+ GitHub Actions checks the Docker HEALTHCHECK status of service containers
30
+ before allowing dependent job steps to run. If the container does not
31
+ transition to `healthy` within the runner's fixed retry window, the job
32
+ fails with "service is unhealthy".
33
+
34
+ This commonly occurs because:
35
+ 1. **No options specified** — Docker uses the image's built-in HEALTHCHECK,
36
+ which may be missing, too aggressive, or unsuitable for the CI environment.
37
+ 2. **Startup time** — services like PostgreSQL, RabbitMQ, or Elasticsearch
38
+ take longer to initialize on GitHub-hosted runners than on local machines,
39
+ and the default health-check interval/retries expire before they're ready.
40
+ 3. **Wrong health-check command** — a network ping health check may fail if
41
+ the service port isn't yet bound even though the process is running.
42
+ 4. **Missing `--health-start-period`** — without a start period, Docker counts
43
+ health-check failures from container start, before the service has had time
44
+ to initialize.
45
+
46
+ Documented in actions/example-services issue #3.
47
+ fix: |
48
+ Add `options:` to the service container definition with explicit health-check
49
+ parameters suited to the service and GitHub-hosted runner environment:
50
+
51
+ - `--health-cmd`: Use a service-native health check command, not a TCP probe.
52
+ Examples:
53
+ PostgreSQL: `pg_isready -U postgres`
54
+ Redis: `redis-cli ping`
55
+ MySQL: `mysqladmin ping -h localhost`
56
+ RabbitMQ: `rabbitmqctl node_health_check`
57
+
58
+ - `--health-interval 10s`: Check every 10 seconds
59
+ - `--health-timeout 5s`: Allow up to 5 seconds per check
60
+ - `--health-retries 5`: Retry up to 5 times before marking unhealthy
61
+ - `--health-start-period 30s`: Give 30 seconds before counting failures
62
+
63
+ If the image lacks a health check and the options approach is insufficient,
64
+ add an explicit wait step after job start using the service label name to
65
+ poll readiness with a loop.
66
+ fix_code:
67
+ - language: yaml
68
+ label: "PostgreSQL service container with proper health check"
69
+ code: |
70
+ jobs:
71
+ test:
72
+ runs-on: ubuntu-latest
73
+ services:
74
+ postgres:
75
+ image: postgres:16
76
+ env:
77
+ POSTGRES_PASSWORD: postgres
78
+ POSTGRES_DB: testdb
79
+ ports:
80
+ - 5432:5432
81
+ options: >-
82
+ --health-cmd "pg_isready -U postgres"
83
+ --health-interval 10s
84
+ --health-timeout 5s
85
+ --health-retries 5
86
+ --health-start-period 30s
87
+ steps:
88
+ - run: psql postgresql://postgres:postgres@localhost:5432/testdb -c "SELECT 1"
89
+ - language: yaml
90
+ label: "Redis service container with proper health check"
91
+ code: |
92
+ services:
93
+ redis:
94
+ image: redis:7
95
+ ports:
96
+ - 6379:6379
97
+ options: >-
98
+ --health-cmd "redis-cli ping"
99
+ --health-interval 10s
100
+ --health-timeout 5s
101
+ --health-retries 5
102
+ - language: yaml
103
+ label: "Fallback — explicit wait step if health check unreliable"
104
+ code: |
105
+ steps:
106
+ - name: Wait for PostgreSQL to be ready
107
+ run: |
108
+ until pg_isready -h localhost -p 5432 -U postgres; do
109
+ echo "Waiting for postgres..."
110
+ sleep 2
111
+ done
112
+ timeout-minutes: 2
113
+ prevention:
114
+ - "Always specify `options:` with `--health-cmd`, `--health-interval`, `--health-retries`, and `--health-start-period` for every service container."
115
+ - "Use service-native health check commands (pg_isready, redis-cli ping) rather than generic TCP probes."
116
+ - "Add `--health-start-period` of 20-30 seconds for services with slow initialization (PostgreSQL, Elasticsearch, RabbitMQ)."
117
+ - "Test health check timing locally in Docker before relying on it in CI: `docker run --health-cmd '...' --health-interval 5s <image>`."
118
+ docs:
119
+ - url: "https://docs.github.com/en/actions/using-containerized-services/about-service-containers"
120
+ label: "About service containers"
121
+ - url: "https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idservicesservice_idoptions"
122
+ label: "Workflow syntax — services options"
123
+ - url: "https://github.com/actions/example-services/issues/3"
124
+ label: "actions/example-services #3 — Service container health check questions and fixes"
125
+ - url: "https://stackoverflow.com/questions/66763353/how-to-health-check-a-service-in-github"
126
+ label: "Stack Overflow — How to health check a service in GitHub Actions"
@@ -0,0 +1,131 @@
1
+ id: runner-environment-020
2
+ title: "windows-latest Now Uses Visual Studio 2026 — VS 2022 Components Removed"
3
+ category: runner-environment
4
+ severity: error
5
+ tags:
6
+ - windows
7
+ - visual-studio
8
+ - runner-image
9
+ - breaking-change
10
+ - msbuild
11
+ - dotnet
12
+ patterns:
13
+ - regex: "MSB[0-9]+.*Visual Studio 2022|The tools version.*15\\.0.*is not available"
14
+ flags: "i"
15
+ - regex: "Dotfuscator.*not found|dotfuscator.*missing"
16
+ flags: "i"
17
+ - regex: "Component.*Azure.ServiceFabric.Tools.*not installed"
18
+ flags: "i"
19
+ - regex: "VC\\.Tools\\.ARM.*not found|Microsoft\\.VisualStudio\\.Component\\.VC\\.Tools\\.ARM"
20
+ flags: "i"
21
+ - regex: "error.*NETSDK1045.*The current .NET SDK does not support targeting .NET (5|6|7)"
22
+ flags: "i"
23
+ - regex: "Visual Studio.*version 17\\.[0-9]+.*not found|MSBuild.*17\\.[0-9]+.*not available"
24
+ flags: "i"
25
+ error_messages:
26
+ - "MSB4019: The imported project 'Microsoft.CppBuild.targets' was not found."
27
+ - "Error: Dotfuscator is not installed. Please install Dotfuscator Community."
28
+ - "The component 'Microsoft.VisualStudio.Component.Azure.ServiceFabric.Tools' is not installed."
29
+ - "MSBUILD : error MSB1009: Project file does not exist. Switch: /version:17"
30
+ - "The current .NET SDK does not support targeting .NET 7.0."
31
+ root_cause: |
32
+ The `windows-latest` and `windows-2025` labels in GitHub Actions were migrated to use
33
+ **Windows Server 2025 with Visual Studio 2026** beginning June 8, 2026 (completing
34
+ June 15, 2026). Previously these labels ran Visual Studio 2022 (version 17.x).
35
+
36
+ Visual Studio 2026 (version 18.x) ships with MSBuild 18 and removes several VS 2022
37
+ components that workflows may depend on:
38
+
39
+ **Removed VS components:**
40
+ - `Component.Dotfuscator` — .NET obfuscation tool
41
+ - `Microsoft.VisualStudio.Component.Azure.ServiceFabric.Tools`
42
+ - `Microsoft.VisualStudio.Component.TestTools.CodedUITest`
43
+ - `Microsoft.VisualStudio.Component.TestTools.WebLoadTest`
44
+ - `Microsoft.VisualStudio.Component.VC.Tools.ARM` — ARM cross-compilation toolchain
45
+ - `Microsoft.VisualStudio.Component.VC.Modules.x86.x64`
46
+ - `Microsoft.VisualStudio.Component.VC.Runtimes.ARM.Spectre`
47
+ - `Microsoft.VisualStudio.Component.VC.MFC.ARM` and `.ARM.Spectre`
48
+ - `Microsoft.VisualStudio.Component.VC.ATL.ARM` and `.ARM.Spectre`
49
+ - `Microsoft.VisualStudio.ComponentGroup.Azure.CloudServices`
50
+ - `Microsoft.VisualStudio.ComponentGroup.Azure.ResourceManager.Tools`
51
+
52
+ **Other changes:**
53
+ - CMake updated from 3.31.6 → 4.3.2 (adds VS 18 2026 generator, deprecates some older generators)
54
+ - Android Command Line Tools updated from 16.0 → 19.0
55
+ - MSVC v143 toolset is added as a compatibility shim for projects requiring it
56
+ fix: |
57
+ **Immediate rollback:** Pin to `windows-2022` to keep Visual Studio 2022:
58
+ ```yaml
59
+ runs-on: windows-2022
60
+ ```
61
+ Note: `windows-2022` continues to run VS 2022 (version 17.x) and will remain supported.
62
+
63
+ **For removed components:**
64
+ - **Dotfuscator**: Remove from build pipeline, or install manually via the Dotfuscator
65
+ Community installer in a workflow step. Consider alternatives like ConfuserEx.
66
+ - **ARM VC toolchain** (`VC.Tools.ARM`): Use the separate `windows-11-arm64` runner label
67
+ for native ARM64 builds, or cross-compile via MSVC v143 shim that ships with VS 2026.
68
+ - **Azure Service Fabric Tools**: Install the Service Fabric SDK directly via PowerShell
69
+ if your workflow requires it.
70
+ - **CMake generator**: Update your CMake invocation from `-G "Visual Studio 17 2022"` to
71
+ `-G "Visual Studio 18 2026"`.
72
+ fix_code:
73
+ - language: yaml
74
+ label: "Pin to windows-2022 for immediate rollback (VS 2022)"
75
+ code: |
76
+ jobs:
77
+ build:
78
+ # Temporarily pin to VS 2022 while migrating
79
+ runs-on: windows-2022
80
+ steps:
81
+ - uses: actions/checkout@v4
82
+ - name: Build
83
+ run: msbuild MyProject.sln /p:Configuration=Release
84
+ - language: yaml
85
+ label: "Migrate to VS 2026 — update CMake generator and toolset"
86
+ code: |
87
+ jobs:
88
+ build:
89
+ runs-on: windows-latest # now VS 2026
90
+ steps:
91
+ - uses: actions/checkout@v4
92
+
93
+ - name: Configure CMake (VS 2026 generator)
94
+ run: |
95
+ cmake -B build -G "Visual Studio 18 2026" -A x64 `
96
+ -DCMAKE_BUILD_TYPE=Release
97
+
98
+ - name: Build
99
+ run: cmake --build build --config Release
100
+
101
+ # If you need MSVC v143 (VS 2022 toolset) compatibility:
102
+ # cmake -B build -G "Visual Studio 18 2026" -A x64 -T v143
103
+ - language: yaml
104
+ label: "Test against both VS 2022 and VS 2026 during migration"
105
+ code: |
106
+ jobs:
107
+ build:
108
+ strategy:
109
+ matrix:
110
+ os: [windows-2022, windows-latest]
111
+ runs-on: ${{ matrix.os }}
112
+ steps:
113
+ - uses: actions/checkout@v4
114
+ - name: Build and test
115
+ run: msbuild MyProject.sln /p:Configuration=Release /t:Build,Test
116
+ prevention:
117
+ - "Avoid depending on specific Visual Studio components that are not part of the core VS 2022/2026 workloads — install them explicitly in your workflow if needed."
118
+ - "Subscribe to actions/runner-images announcements to receive advance notice of `windows-latest` migrations."
119
+ - "Test your Windows workflows against `windows-2025-vs2026` before the `windows-latest` migration completes."
120
+ - "Use MSBuild's `-T v143` toolset flag to target the VS 2022 compiler toolchain from within VS 2026 if full migration is not yet feasible."
121
+ - "Search your workflows for CMake generator strings like 'Visual Studio 17 2022' and update them proactively."
122
+ docs:
123
+ - url: "https://github.com/actions/runner-images/issues/14017"
124
+ label: "GitHub Announcement: windows-latest migrates to Visual Studio 2026"
125
+ - url: "https://github.com/actions/runner-images/issues/14016"
126
+ label: "GitHub Announcement: Windows Server 2025 with VS 2026 now GA"
127
+ - url: "https://docs.github.com/en/actions/using-github-hosted-runners/using-github-hosted-runners/about-github-hosted-runners"
128
+ label: "About GitHub-hosted runners"
129
+ source:
130
+ article: "https://htek.dev/articles/github-actions-debugging-guide"
131
+ section: "Windows runner Visual Studio migrations"
@@ -0,0 +1,96 @@
1
+ id: silent-failures-009
2
+ title: "hashFiles() Returns Empty String When No Files Match — Silent Cache Key Collision"
3
+ category: silent-failures
4
+ severity: silent-failure
5
+ tags:
6
+ - cache
7
+ - hashFiles
8
+ - cache-key
9
+ - collision
10
+ - glob
11
+ - silent-failure
12
+ patterns:
13
+ - regex: "key: [A-Za-z0-9_-]+-$"
14
+ flags: "m"
15
+ - regex: "Cache restored from key: [A-Za-z0-9_-]+(?!-[0-9a-f]{64})"
16
+ flags: "i"
17
+ error_messages:
18
+ - "Cache restored from key: Linux-node-"
19
+ - "Cache restored from key: Linux-pip-"
20
+ - "No error shown — workflow succeeds but wrong cache is restored"
21
+ root_cause: |
22
+ The `hashFiles()` expression function returns an empty string (not an error)
23
+ when the supplied glob pattern matches no files in the workspace. This silently
24
+ truncates the cache key, turning a key like:
25
+
26
+ ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
27
+
28
+ into:
29
+
30
+ Linux-node-
31
+
32
+ when no package-lock.json exists. This short, predictable key collides across
33
+ branches and runs, causing stale or wrong cache content to be restored without
34
+ any warning. The workflow log shows the cache as restored successfully.
35
+
36
+ Documented in actions/runner issue #894. Commonly triggered by:
37
+ - Lockfile not yet committed (new project setup)
38
+ - Wrong glob path (e.g., `**/package-lock.json` but lockfile is at root)
39
+ - Wrong working directory at cache step execution time
40
+ - Matrix jobs where not all matrix values have a matching lockfile
41
+ fix: |
42
+ Add a fallback value to the hashFiles() expression using the `||` operator so
43
+ the key is always deterministic even when no files match:
44
+
45
+ key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') || 'no-lockfile' }}
46
+
47
+ Also verify that the glob actually matches the file by running
48
+ `find . -name "package-lock.json"` in a debug step before the cache step.
49
+
50
+ For matrix workflows, include the matrix value in the key to prevent
51
+ cross-matrix collisions even when hash is empty:
52
+
53
+ key: ${{ runner.os }}-node-${{ matrix.node-version }}-${{ hashFiles('**/package-lock.json') || 'no-lockfile' }}
54
+ fix_code:
55
+ - language: yaml
56
+ label: "WRONG — hashFiles with no fallback (silently short key on miss)"
57
+ code: |
58
+ - uses: actions/cache@v4
59
+ with:
60
+ path: ~/.npm
61
+ key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
62
+ # ❌ If no package-lock.json found, key becomes "Linux-node-"
63
+ # All runs share the same truncated key → wrong cache restored silently
64
+ - language: yaml
65
+ label: "RIGHT — hashFiles with explicit fallback"
66
+ code: |
67
+ - uses: actions/cache@v4
68
+ with:
69
+ path: ~/.npm
70
+ key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') || 'no-lockfile' }}
71
+ # ✅ If no lockfile, key becomes "Linux-node-no-lockfile" — deterministic and unique
72
+ restore-keys: |
73
+ ${{ runner.os }}-node-
74
+ - language: yaml
75
+ label: "DEBUG — verify glob matches before caching"
76
+ code: |
77
+ - name: Debug — check lockfile exists
78
+ run: find . -name "package-lock.json" | head -5
79
+ # If empty output: fix the glob or ensure lockfile is committed
80
+
81
+ - uses: actions/cache@v4
82
+ with:
83
+ path: ~/.npm
84
+ key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') || 'no-lockfile' }}
85
+ prevention:
86
+ - "Always provide a `|| 'fallback-value'` after any hashFiles() call to prevent empty-string cache key truncation."
87
+ - "Test your hashFiles() glob locally: run `find . -name 'your-lockfile'` from the repo root to confirm it matches."
88
+ - "Include stable discriminators (runner.os, matrix values, Node version) in cache keys to reduce collision risk."
89
+ - "Review restored cache key in workflow logs — a key ending in just a short prefix without a 64-char hash is a sign of an empty hashFiles()."
90
+ docs:
91
+ - url: "https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/evaluate-expressions-in-workflows-and-actions#hashfiles"
92
+ label: "hashFiles() function documentation"
93
+ - url: "https://github.com/actions/runner/issues/894"
94
+ label: "actions/runner #894 — hashFiles returns empty string instead of hash"
95
+ - url: "https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows"
96
+ label: "Caching dependencies to speed up workflows"
@@ -0,0 +1,105 @@
1
+ id: triggers-006
2
+ title: "Job Blocked Silently by Environment Protection Rules — No Clear Log Message"
3
+ category: triggers
4
+ severity: warning
5
+ tags:
6
+ - environment
7
+ - protection-rules
8
+ - deployment
9
+ - approval
10
+ - branch-restriction
11
+ - silent-wait
12
+ patterns:
13
+ - regex: "Waiting for.*environment.*approval"
14
+ flags: "i"
15
+ - regex: "Branch '.*' is not allowed to deploy to .* due to environment protection rules"
16
+ flags: "i"
17
+ - regex: "Expected.*Waiting for status to be reported"
18
+ flags: "i"
19
+ error_messages:
20
+ - "Branch 'feature/my-branch' is not allowed to deploy to production due to environment protection rules."
21
+ - "Waiting for approval — This workflow run requires approval from the environment's configured reviewers."
22
+ - "Expected — Waiting for status to be reported"
23
+ root_cause: |
24
+ GitHub Environments can have protection rules that gate job execution:
25
+ - **Required reviewers**: A human must approve the deployment before the job runs.
26
+ - **Branch/tag restrictions**: Only specific branches or tags are allowed to
27
+ deploy to the environment (e.g., only `main` can deploy to `production`).
28
+ - **Required status checks**: External status checks must pass first.
29
+ - **Wait timers**: A mandatory delay before the job can proceed.
30
+
31
+ When a job targets an environment with unsatisfied protection rules, it enters
32
+ a waiting state in the GitHub UI. The **workflow log may not show a clear
33
+ failure message** — the job simply appears as pending or "Expected — Waiting
34
+ for status to be reported." This is a common source of confusion for teams
35
+ that enable environment protection rules for the first time, especially in
36
+ forks or feature-branch workflows where the branch is not in the allowed list.
37
+
38
+ Documented in GitHub Community discussions #39054 and #26698.
39
+ fix: |
40
+ 1. **Check environment settings**: Repository Settings → Environments → select
41
+ the environment → review protection rules (required reviewers, deployment
42
+ branches, required checks, wait timers).
43
+
44
+ 2. **For branch restriction failures**: Add the branch that the workflow runs
45
+ on to the environment's "Deployment branches and tags" list, or change the
46
+ policy to "No restriction" for non-production environments.
47
+
48
+ 3. **For pending approval**: A configured reviewer must approve the deployment
49
+ in the GitHub UI (Actions tab → select the run → click "Review deployments").
50
+
51
+ 4. **For automated CI**: Use a separate environment with no protection rules
52
+ for automated test deployments, and reserve protected environments for
53
+ production deployments that require human approval.
54
+
55
+ 5. **For fork PRs**: Environments with protection rules can silently block
56
+ fork PRs since the fork branch is not in the allowed branch list — use a
57
+ separate no-protection environment for fork PR validation jobs.
58
+ fix_code:
59
+ - language: yaml
60
+ label: "Use separate environments for CI vs production"
61
+ code: |
62
+ jobs:
63
+ deploy-staging:
64
+ runs-on: ubuntu-latest
65
+ environment: staging # ✅ no protection rules — runs immediately
66
+ steps:
67
+ - run: ./deploy.sh staging
68
+
69
+ deploy-production:
70
+ needs: deploy-staging
71
+ runs-on: ubuntu-latest
72
+ environment: production # 🔒 has required reviewers — waits for approval
73
+ if: github.ref == 'refs/heads/main' # ✅ only main is in allowed branch list
74
+ steps:
75
+ - run: ./deploy.sh production
76
+ - language: yaml
77
+ label: "Check branch restriction: ensure workflow branch is in allowed list"
78
+ code: |
79
+ # In GitHub UI: Settings → Environments → production → Deployment branches
80
+ # Add "main" or change policy to match your workflow's ref.
81
+ #
82
+ # In workflow: use github.ref_name to verify before targeting environment
83
+ jobs:
84
+ deploy:
85
+ runs-on: ubuntu-latest
86
+ # Only run on main — matches production environment's branch restriction
87
+ if: github.ref == 'refs/heads/main'
88
+ environment: production
89
+ steps:
90
+ - run: ./deploy.sh
91
+ prevention:
92
+ - "Document environment protection rules in your repository's CONTRIBUTING.md so all developers know which branches can deploy where."
93
+ - "Test protection rules in a staging environment before applying them to production — the silent-wait behavior is surprising on first encounter."
94
+ - "For automated CI workflows that run on feature branches, use environments without branch restrictions or required reviewers."
95
+ - "After enabling environment protection rules, verify the workflow can actually trigger by running a test deployment from an allowed branch."
96
+ - "Monitor for stuck jobs in the Actions tab — a job sitting in 'waiting' or 'Expected' state usually means an environment protection rule is blocking it."
97
+ docs:
98
+ - url: "https://docs.github.com/en/actions/deployment/targeting-different-environments/using-environments-for-deployment"
99
+ label: "Using environments for deployment — protection rules"
100
+ - url: "https://github.com/orgs/community/discussions/39054"
101
+ label: "GitHub Community #39054 — Branch not allowed to deploy due to environment protection rules"
102
+ - url: "https://github.com/orgs/community/discussions/26698"
103
+ label: "GitHub Community #26698 — Job stuck in Expected / Waiting for status to be reported"
104
+ - url: "https://stackoverflow.com/questions/72109150/github-action-avoid-approval-on-same-environment-rule-within-same-workflow"
105
+ label: "Stack Overflow — Avoiding approval in same environment within same workflow"
@@ -0,0 +1,109 @@
1
+ id: yaml-syntax-014
2
+ title: "env Context Not Available at Job-Level if or Reusable Workflow Positions"
3
+ category: yaml-syntax
4
+ severity: error
5
+ tags:
6
+ - env
7
+ - context
8
+ - job-if
9
+ - reusable-workflow
10
+ - expression
11
+ - context-availability
12
+ patterns:
13
+ - regex: "Unrecognized named-value: 'env'"
14
+ flags: "i"
15
+ - regex: "The workflow is not valid.*Unrecognized named-value: 'env'"
16
+ flags: "i"
17
+ - regex: "Located at position \\d+ within expression.*env\\."
18
+ flags: "i"
19
+ error_messages:
20
+ - "The workflow is not valid. .github/workflows/<workflow>.yml (Line: X, Col: Y): Unrecognized named-value: 'env'. Located at position Z within expression: <expression>"
21
+ - "Unrecognized named-value: 'env'. Located at position 1 within expression"
22
+ root_cause: |
23
+ GitHub Actions evaluates job-level expressions (jobs.<job_id>.if, certain
24
+ jobs.<job_id>.with: inputs for reusable workflows) before any steps run and
25
+ before step-level env values are available. Because the `env` context is
26
+ only populated at step execution time, using `env.MY_VAR` inside a job-level
27
+ `if:` condition or inside a reusable workflow's `jobs:` block triggers a
28
+ validation error at parse time rather than a runtime failure.
29
+
30
+ This affects:
31
+ - `jobs.<job_id>.if: ${{ env.MY_VAR == 'foo' }}`
32
+ - `jobs.<job_id>.with:` fields referencing `env.*` in a reusable workflow call
33
+ - Any top-level workflow expression that attempts to read `env` context
34
+
35
+ Documented in actions/runner issues #1189, #1661, and #2372.
36
+ fix: |
37
+ Replace env context references in job-level positions with contexts that are
38
+ available at job evaluation time:
39
+ - Use `vars.*` (repository/environment variables) for static configuration values
40
+ - Use `github.*` context for event-driven values
41
+ - Use `inputs.*` for values passed into reusable workflows
42
+ - Use job outputs (`needs.<job_id>.outputs.<name>`) to pass dynamic values
43
+ computed in earlier steps to downstream job `if:` conditions
44
+
45
+ If the value is truly dynamic and set in a previous step, emit it as a step
46
+ output → job output → needs output chain so downstream jobs can reference it.
47
+ fix_code:
48
+ - language: yaml
49
+ label: "WRONG — env context in job-level if (fails validation)"
50
+ code: |
51
+ jobs:
52
+ deploy:
53
+ if: ${{ env.DEPLOY_ENV == 'production' }} # ❌ env not available here
54
+ runs-on: ubuntu-latest
55
+ steps:
56
+ - run: echo "Deploying"
57
+ - language: yaml
58
+ label: "RIGHT — use vars context or job outputs instead"
59
+ code: |
60
+ # Option 1: use vars (repository/environment variables) for static config
61
+ jobs:
62
+ deploy:
63
+ if: ${{ vars.DEPLOY_ENV == 'production' }} # ✅ vars available at job level
64
+ runs-on: ubuntu-latest
65
+ steps:
66
+ - run: echo "Deploying"
67
+
68
+ # Option 2: compute in a preceding job, emit as output
69
+ jobs:
70
+ compute-env:
71
+ runs-on: ubuntu-latest
72
+ outputs:
73
+ deploy_env: ${{ steps.set-env.outputs.deploy_env }}
74
+ steps:
75
+ - id: set-env
76
+ run: echo "deploy_env=production" >> $GITHUB_OUTPUT
77
+
78
+ deploy:
79
+ needs: compute-env
80
+ if: ${{ needs.compute-env.outputs.deploy_env == 'production' }}
81
+ runs-on: ubuntu-latest
82
+ steps:
83
+ - run: echo "Deploying"
84
+ - language: yaml
85
+ label: "RIGHT — reusable workflow: pass value via inputs not env"
86
+ code: |
87
+ # Caller workflow
88
+ jobs:
89
+ call-deploy:
90
+ uses: ./.github/workflows/deploy.yml
91
+ with:
92
+ environment: production # ✅ pass via inputs, not env
93
+ secrets: inherit
94
+ prevention:
95
+ - "Consult the GitHub docs context availability table before writing expressions — not all contexts are available at every YAML key position."
96
+ - "For job-level if conditions, use `vars.*`, `github.*`, or `needs.<job>.outputs.*` — never `env.*`."
97
+ - "For reusable workflow inputs, pass values explicitly through `with:` inputs rather than relying on caller env context."
98
+ - "Use `vars` (repository/environment variables) as a replacement for env-based feature flags that need to be available at job evaluation time."
99
+ docs:
100
+ - url: "https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/accessing-contextual-information-about-workflow-runs#context-availability"
101
+ label: "Context availability — which contexts are available at each YAML key"
102
+ - url: "https://github.com/actions/runner/issues/1189"
103
+ label: "actions/runner #1189 — Unrecognized named-value: 'env' for job conditional"
104
+ - url: "https://github.com/actions/runner/issues/1661"
105
+ label: "actions/runner #1661 — env unrecognised in job-level if when calling reusable workflow"
106
+ - url: "https://github.com/actions/runner/issues/2372"
107
+ label: "actions/runner #2372 — Unrecognized named-value: 'env' in reusable workflow jobs"
108
+ - url: "https://stackoverflow.com/questions/76471787/why-is-env-context-not-available-in-github-action-job-level-if-statement"
109
+ label: "Stack Overflow — Why is env context not available in job level if statement?"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@htekdev/actions-debugger",
3
- "version": "1.0.2",
3
+ "version": "1.0.3",
4
4
  "description": "65+ real GitHub Actions errors, queryable by agents. MCP server + Copilot skills + error database.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",