@htekdev/actions-debugger 1.0.10 → 1.0.11

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,120 @@
1
+ id: caching-artifacts-013
2
+ title: "Cross-OS Cache Miss — enableCrossOsArchive Not Set"
3
+ category: caching-artifacts
4
+ severity: silent-failure
5
+ tags:
6
+ - cache
7
+ - cross-os
8
+ - windows
9
+ - linux
10
+ - cache-miss
11
+ - enableCrossOsArchive
12
+ patterns:
13
+ - regex: "Cache not found for input keys"
14
+ flags: "i"
15
+ - regex: "enableCrossOsArchive.*false"
16
+ flags: "i"
17
+ - regex: "cache miss.*windows"
18
+ flags: "i"
19
+ - regex: "tar.*posix.*failed"
20
+ flags: "i"
21
+ error_messages:
22
+ - "Cache not found for input keys: <key>"
23
+ - "enableCrossOsArchive: false"
24
+ - "Cache saved successfully"
25
+ - "Post job cleanup."
26
+ root_cause: |
27
+ `actions/cache` uses different archive formats depending on the runner OS:
28
+ - Linux/macOS: GNU tar (gnutar) with zstd compression
29
+ - Windows: BSD tar bundled with Git for Windows (`C:\Program Files\Git\usr\bin\tar.exe`)
30
+
31
+ When a cache is created on Linux or macOS, the archive is in GNU tar format. When
32
+ Windows attempts to restore it (or vice versa), the different tar implementation
33
+ fails to decompress the archive, resulting in a silent cache miss.
34
+
35
+ The `enableCrossOsArchive` option (default: `false`) controls whether the cache is
36
+ stored in a cross-platform-compatible format. Setting it to `true` forces GNU tar
37
+ format on all platforms, enabling cache sharing across OSes.
38
+
39
+ This is particularly common in monorepos where:
40
+ - Node modules or package caches are written by a Linux job and expected to be
41
+ restored by a Windows job in the same workflow run
42
+ - A "seed cache" job runs on Linux and downstream jobs run on Windows
43
+ - The matrix includes multiple OS values sharing the same cache key
44
+
45
+ Tracked in actions/cache#1275 (Cache miss on Windows despite a successful
46
+ cache-write) — confirmed fixed by setting `enableCrossOsArchive: true`.
47
+ fix: |
48
+ Add `enableCrossOsArchive: true` to ALL cache steps (both the write and the restore
49
+ steps) that need to share caches across different OS runners.
50
+
51
+ IMPORTANT: The option must be set consistently on both the writing and reading jobs.
52
+ Setting it only on one side will not work.
53
+
54
+ If true cross-OS caching is not needed, ensure each OS creates its own native cache
55
+ by including `${{ runner.os }}` in the cache key.
56
+ fix_code:
57
+ - language: yaml
58
+ label: "Enable cross-OS archive on cache steps that share between Linux and Windows"
59
+ code: |
60
+ - name: Cache node modules (cross-OS compatible)
61
+ uses: actions/cache@v4
62
+ with:
63
+ path: node_modules
64
+ key: node-${{ hashFiles('**/package-lock.json') }}
65
+ enableCrossOsArchive: true # Required for Linux↔Windows cache sharing
66
+
67
+ - language: yaml
68
+ label: "OS-specific cache keys (alternative — each OS gets its own cache)"
69
+ code: |
70
+ - name: Cache dependencies (OS-scoped key — no cross-OS needed)
71
+ uses: actions/cache@v4
72
+ with:
73
+ path: ~/.cache/pip
74
+ # Include runner.os so each OS writes its own cache entry
75
+ key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
76
+ restore-keys: |
77
+ ${{ runner.os }}-pip-
78
+
79
+ - language: yaml
80
+ label: "Matrix workflow with consistent enableCrossOsArchive on all jobs"
81
+ code: |
82
+ jobs:
83
+ seed-cache:
84
+ runs-on: ubuntu-latest
85
+ steps:
86
+ - uses: actions/checkout@v4
87
+ - name: Seed shared cache
88
+ uses: actions/cache@v4
89
+ with:
90
+ path: node_modules
91
+ key: node-${{ hashFiles('**/package-lock.json') }}
92
+ enableCrossOsArchive: true
93
+
94
+ build:
95
+ needs: seed-cache
96
+ strategy:
97
+ matrix:
98
+ os: [ubuntu-latest, windows-latest]
99
+ runs-on: ${{ matrix.os }}
100
+ steps:
101
+ - uses: actions/checkout@v4
102
+ - name: Restore shared cache
103
+ uses: actions/cache@v4
104
+ with:
105
+ path: node_modules
106
+ key: node-${{ hashFiles('**/package-lock.json') }}
107
+ enableCrossOsArchive: true # Must match the write job
108
+
109
+ prevention:
110
+ - "Always include `runner.os` in your cache key unless you explicitly need cross-OS sharing."
111
+ - "When cross-OS sharing IS required, set `enableCrossOsArchive: true` on every step that reads or writes the shared cache."
112
+ - "Treat cross-OS cache sharing as an explicit opt-in, not the default."
113
+ - "Test cache restoration on all target OSes during initial workflow setup."
114
+ docs:
115
+ - url: "https://github.com/actions/cache/blob/main/README.md"
116
+ label: "actions/cache README: enableCrossOsArchive option"
117
+ - url: "https://github.com/actions/cache/blob/main/tips-and-workarounds.md"
118
+ label: "actions/cache: Tips and workarounds (cross-OS section)"
119
+ - url: "https://github.com/actions/cache/issues/1275"
120
+ label: "actions/cache#1275: Cache miss on Windows despite a successful cache-write"
@@ -0,0 +1,124 @@
1
+ id: runner-environment-032
2
+ title: "persist-credentials: false Breaks Subsequent Git Push / Authentication"
3
+ category: runner-environment
4
+ severity: error
5
+ tags:
6
+ - checkout
7
+ - persist-credentials
8
+ - git-push
9
+ - authentication
10
+ - credential-helper
11
+ - git-auto-commit
12
+ patterns:
13
+ - regex: "fatal:.*could not read Username.*No such device"
14
+ flags: "i"
15
+ - regex: "fatal: Authentication failed for.*github\\.com"
16
+ flags: "i"
17
+ - regex: "remote:.*Invalid username or password"
18
+ flags: "i"
19
+ - regex: "persist-credentials.*false"
20
+ flags: "i"
21
+ - regex: "error: The requested URL returned error: 403"
22
+ flags: "i"
23
+ error_messages:
24
+ - "fatal: could not read Username for 'https://github.com': No such device or address"
25
+ - "fatal: Authentication failed for 'https://github.com/owner/repo.git/'"
26
+ - "remote: Invalid username or password."
27
+ - "error: The requested URL returned error: 403"
28
+ - "remote: Support for password authentication was removed"
29
+ root_cause: |
30
+ When `actions/checkout` runs with `persist-credentials: false`, it:
31
+ 1. Checks out the repository
32
+ 2. Explicitly **removes** the git credential helper that was configured for GITHUB_TOKEN auth
33
+ 3. Leaves the working directory with no way to authenticate subsequent git operations
34
+
35
+ Any `git push`, `git pull`, or `git fetch` call that runs AFTER this checkout will
36
+ fail with an authentication error because there is no credential helper configured.
37
+
38
+ This pattern is often introduced deliberately for security (to avoid GITHUB_TOKEN
39
+ persistence), but developers forget that it also breaks any action or step that needs
40
+ to push changes back to the repository — such as:
41
+ - `stefanzweifel/git-auto-commit-action` (fails with "could not read Username")
42
+ - Manual `git push origin HEAD` steps
43
+ - Semantic-release, release-please, and other auto-committing tools
44
+ - Actions that amend, tag, or push version bumps
45
+
46
+ The issue is also triggered transitively: if a composite action internally calls
47
+ `actions/checkout` with `persist-credentials: false`, the credential helper is
48
+ removed from the runner's git config, breaking git auth for all subsequent steps.
49
+
50
+ Tracked across multiple issues: stefanzweifel/git-auto-commit-action#356,
51
+ stefanzweifel/git-auto-commit-action#397, anthropics/claude-code-action#1236.
52
+ fix: |
53
+ **Option 1 (simplest): Remove persist-credentials: false**
54
+ If you set it out of habit or from a template, just remove it. GITHUB_TOKEN credentials
55
+ stored by actions/checkout are scoped to the runner and do not persist beyond the
56
+ workflow run anyway.
57
+
58
+ **Option 2: Re-configure credentials after checkout**
59
+ If you need `persist-credentials: false` for security reasons (e.g., to prevent
60
+ GITHUB_TOKEN from being used by untrusted code), re-add credentials only for the
61
+ steps that need to push.
62
+
63
+ **Option 3: Use SSH instead of HTTPS**
64
+ Configure SSH deploy keys and use an SSH remote URL to avoid HTTPS credential
65
+ issues entirely.
66
+ fix_code:
67
+ - language: yaml
68
+ label: "Remove persist-credentials: false (simplest fix)"
69
+ code: |
70
+ - uses: actions/checkout@v4
71
+ with:
72
+ # REMOVE this line — credentials are scoped to the runner by default
73
+ # persist-credentials: false
74
+
75
+ - name: Commit and push changes
76
+ run: |
77
+ git config user.name "github-actions[bot]"
78
+ git config user.email "github-actions[bot]@users.noreply.github.com"
79
+ git add .
80
+ git commit -m "chore: auto-update generated files [skip ci]"
81
+ git push
82
+
83
+ - language: yaml
84
+ label: "Re-configure credentials after persist-credentials: false (security-first workflows)"
85
+ code: |
86
+ - uses: actions/checkout@v4
87
+ with:
88
+ persist-credentials: false # Untrusted code runs between here and push
89
+
90
+ # ... run untrusted/third-party code here ...
91
+
92
+ - name: Re-configure GITHUB_TOKEN for push
93
+ run: |
94
+ git remote set-url origin https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}
95
+ # Now git push will work again
96
+
97
+ - name: Push changes
98
+ run: git push
99
+
100
+ - language: yaml
101
+ label: "Use PAT or app token to push (avoids GITHUB_TOKEN limitations)"
102
+ code: |
103
+ - uses: actions/checkout@v4
104
+ with:
105
+ token: ${{ secrets.MY_PAT }} # Use a PAT that has write access
106
+ persist-credentials: true # Default: true — keep this to allow push
107
+
108
+ - name: Push changes
109
+ run: git push
110
+
111
+ prevention:
112
+ - "Do not add `persist-credentials: false` unless you have a specific security reason (e.g., running untrusted fork code)."
113
+ - "If any step after `actions/checkout` needs to push commits or tags, ensure credentials are persisted or re-configured."
114
+ - "When using `git-auto-commit-action` or similar, check upstream docs for compatibility with `persist-credentials: false`."
115
+ - "Prefer `token: ${{ secrets.GITHUB_TOKEN }}` with `persist-credentials: true` over re-configuring remote URLs manually."
116
+ docs:
117
+ - url: "https://github.com/actions/checkout#usage"
118
+ label: "actions/checkout: persist-credentials input"
119
+ - url: "https://github.com/stefanzweifel/git-auto-commit-action/discussions/356"
120
+ label: "git-auto-commit-action#356: persist-credentials: false compatibility"
121
+ - url: "https://github.com/stefanzweifel/git-auto-commit-action/issues/397"
122
+ label: "git-auto-commit-action#397: fatal: could not read Username (checkout v5)"
123
+ - url: "https://github.com/anthropics/claude-code-action/issues/1236"
124
+ label: "claude-code-action#1236: fails when persist-credentials: false"
@@ -0,0 +1,104 @@
1
+ id: silent-failures-013
2
+ title: "Shallow Clone (fetch-depth: 1) Silently Breaks Git History Operations"
3
+ category: silent-failures
4
+ severity: silent-failure
5
+ tags:
6
+ - checkout
7
+ - fetch-depth
8
+ - shallow-clone
9
+ - git-describe
10
+ - changelog
11
+ - versioning
12
+ patterns:
13
+ - regex: "fatal:.*No names found.*cannot describe anything"
14
+ flags: "i"
15
+ - regex: "fatal:.*no tag can describe"
16
+ flags: "i"
17
+ - regex: "git describe.*failed with exit code 128"
18
+ flags: "i"
19
+ - regex: "fetch-depth.*1"
20
+ flags: "i"
21
+ error_messages:
22
+ - "fatal: No names found, cannot describe anything."
23
+ - "fatal: no tag can describe ''"
24
+ - "error: process completed with exit code 128"
25
+ - "git describe --tags --abbrev=0 failed"
26
+ root_cause: |
27
+ `actions/checkout` defaults to `fetch-depth: 1`, which creates a shallow clone containing
28
+ only the most recent commit. This means:
29
+ - No commit history beyond the latest commit is available
30
+ - No tags are fetched (unless `fetch-tags: true` is set separately)
31
+ - Git operations that need history context fail silently or produce wrong results
32
+
33
+ Affected operations include:
34
+ - `git describe --tags` — fails with "No names found, cannot describe anything"
35
+ - `git log --oneline HEAD~10..HEAD` — returns nothing or errors
36
+ - Semantic versioning tools (semantic-release, standard-version, release-please)
37
+ - Changelog generators that diff HEAD against previous tags
38
+ - `git rev-list --count HEAD` — returns "1" instead of full commit count
39
+ - GitVersion, MinVer, and similar tag-based version calculators
40
+
41
+ The failure is silent in many cases: the step appears to succeed, but produces an
42
+ empty string, "0.0.0", or a fallback version instead of the expected semver.
43
+
44
+ Tracked in actions/checkout#217 (RFC: fetch-depth: 1 and not cloning tags are dangerous
45
+ defaults) with 22 thumbs-up reactions.
46
+ fix: |
47
+ **Option 1 (recommended for most cases): Fetch full history**
48
+ Set `fetch-depth: 0` to fetch all commits and tags.
49
+
50
+ **Option 2: Fetch only enough history**
51
+ For large repos, fetch only the depth needed (e.g., last 50 commits). Use
52
+ `fetch-tags: true` (available in actions/checkout@v4) to fetch all tags without
53
+ the full commit history.
54
+
55
+ **Option 3: Unshallow after checkout**
56
+ Fetch the necessary history lazily with `git fetch --unshallow` or
57
+ `git fetch --tags --unshallow` as a subsequent step.
58
+ fix_code:
59
+ - language: yaml
60
+ label: "Full history checkout (simplest fix)"
61
+ code: |
62
+ - uses: actions/checkout@v4
63
+ with:
64
+ fetch-depth: 0 # 0 = full history; default 1 = shallow
65
+
66
+ - name: Generate changelog
67
+ run: git log --oneline $(git describe --tags --abbrev=0 @^)..@ --no-merges
68
+
69
+ - language: yaml
70
+ label: "Fetch tags only without full history (faster for large repos)"
71
+ code: |
72
+ - uses: actions/checkout@v4
73
+ with:
74
+ fetch-depth: 0 # Required for tag-based versioning
75
+ fetch-tags: true # Explicitly fetch all tags (actions/checkout v4.1.1+)
76
+
77
+ - language: yaml
78
+ label: "Unshallow lazily if full history is not needed upfront"
79
+ code: |
80
+ - uses: actions/checkout@v4
81
+ # fetch-depth: 1 (default — shallow clone)
82
+
83
+ - name: Fetch tags for versioning
84
+ run: |
85
+ git fetch --tags --force
86
+ # Or for full history:
87
+ # git fetch --unshallow
88
+
89
+ - name: Get version from tags
90
+ run: git describe --tags --abbrev=0
91
+
92
+ prevention:
93
+ - "Add `fetch-depth: 0` to any checkout step that precedes git history, tag, or versioning operations."
94
+ - "Set `fetch-tags: true` in actions/checkout@v4 when using tag-based versioning tools."
95
+ - "When using semantic-release, release-please, or GitVersion, always use `fetch-depth: 0`."
96
+ - "Test locally with `git clone --depth 1` to reproduce the shallow clone environment before debugging in CI."
97
+ - "Audit all checkout steps in release workflows — shallow clones are fine for build/test but break release automation."
98
+ docs:
99
+ - url: "https://github.com/actions/checkout#usage"
100
+ label: "actions/checkout: fetch-depth and fetch-tags inputs"
101
+ - url: "https://github.com/actions/checkout/issues/217"
102
+ label: "actions/checkout#217: RFC — fetch-depth: 1 and not cloning tags are dangerous defaults"
103
+ - url: "https://stackoverflow.com/questions/66349002/get-latest-tag-git-describe-tags-when-repo-is-cloned-with-depth-1"
104
+ label: "Stack Overflow: git describe fails when cloned with depth=1"
@@ -0,0 +1,131 @@
1
+ id: triggers-011
2
+ title: "workflow_dispatch branches/paths Filters Silently Ignored or Cause Validation Error"
3
+ category: triggers
4
+ severity: warning
5
+ tags:
6
+ - workflow_dispatch
7
+ - branches
8
+ - paths
9
+ - filters
10
+ - trigger
11
+ - manual-dispatch
12
+ patterns:
13
+ - regex: "Unexpected value 'branches'"
14
+ flags: "i"
15
+ - regex: "workflow_dispatch.*branches.*paths"
16
+ flags: "i"
17
+ - regex: "The workflow is not valid.*Unexpected value"
18
+ flags: "i"
19
+ - regex: "on\\.workflow_dispatch.*branches"
20
+ flags: "i"
21
+ error_messages:
22
+ - "The workflow is not valid. .github/workflows/deploy.yml (Line: X, Col: Y): Unexpected value 'branches'"
23
+ - "Unexpected value 'branches'"
24
+ - "Unexpected value 'tags'"
25
+ - "Unexpected value 'paths'"
26
+ root_cause: |
27
+ `workflow_dispatch` is a manual trigger — it runs when a user (or the API) explicitly
28
+ triggers the workflow. Because it is not event-driven by a push or pull request, the
29
+ `branches`, `paths`, `tags`, and `paths-ignore` filters that apply to push/pull_request
30
+ events are **not valid** for `workflow_dispatch`.
31
+
32
+ Two failure modes exist:
33
+
34
+ **Mode 1: Validation error (branches, tags)**
35
+ Adding `branches` or `tags` under `on.workflow_dispatch` now produces a schema
36
+ validation error: "Unexpected value 'branches'" or "Unexpected value 'tags'".
37
+ GitHub used to silently ignore these keys (pre-2022), leading to copy-paste templates
38
+ with these keys still floating around. The workflow may fail to queue at all.
39
+
40
+ **Mode 2: Silent ignore (paths)**
41
+ The `paths` filter under `on.workflow_dispatch` was silently ignored historically.
42
+ The workflow runs regardless of which files changed (or didn't change), because
43
+ workflow_dispatch has no file-change context to filter on.
44
+
45
+ Developers commonly copy a push-triggered workflow and add workflow_dispatch without
46
+ removing the push-specific filters, producing this mistake:
47
+
48
+ ```yaml
49
+ on:
50
+ push:
51
+ branches: [main]
52
+ paths: ['src/**']
53
+ workflow_dispatch:
54
+ branches: [main] # ← INVALID for workflow_dispatch
55
+ paths: ['src/**'] # ← silently ignored for workflow_dispatch
56
+ ```
57
+
58
+ Tracked in github/docs#34884 ("documentation on workflow_dispatch is not
59
+ correct/complete") and blog post by Jon Gallant (2022): "workflow_dispatch never
60
+ supported branches, but GH silently ignored it."
61
+ fix: |
62
+ Remove `branches`, `paths`, `tags`, and `paths-ignore` from the `workflow_dispatch`
63
+ block entirely. These filters only apply to `push`, `pull_request`, and
64
+ `pull_request_target` triggers.
65
+
66
+ If you want manual dispatch to only be available on specific branches, use the
67
+ GitHub Actions UI branch selector at runtime — it allows choosing which branch to
68
+ run the workflow on during manual dispatch without needing a filter in the YAML.
69
+
70
+ If you need path-based conditional logic in a manually-triggered workflow, use
71
+ `dorny/paths-filter` or a custom `git diff` step to check which files changed after
72
+ the workflow starts.
73
+ fix_code:
74
+ - language: yaml
75
+ label: "Remove invalid filters from workflow_dispatch block"
76
+ code: |
77
+ on:
78
+ push:
79
+ branches: [main]
80
+ paths: ['src/**'] # ← valid here for push
81
+ workflow_dispatch:
82
+ # ← Do NOT add branches/paths/tags here — they are not supported
83
+ # Use inputs if you need runtime parameterization:
84
+ inputs:
85
+ environment:
86
+ description: "Target environment"
87
+ required: true
88
+ default: "staging"
89
+ type: choice
90
+ options: [staging, production]
91
+
92
+ - language: yaml
93
+ label: "Path-based conditional logic inside a manually-dispatched workflow"
94
+ code: |
95
+ on:
96
+ workflow_dispatch:
97
+
98
+ jobs:
99
+ check-and-deploy:
100
+ runs-on: ubuntu-latest
101
+ steps:
102
+ - uses: actions/checkout@v4
103
+ with:
104
+ fetch-depth: 2
105
+
106
+ - name: Check changed paths
107
+ id: filter
108
+ uses: dorny/paths-filter@v3
109
+ with:
110
+ filters: |
111
+ src:
112
+ - 'src/**'
113
+
114
+ - name: Deploy (only if src changed)
115
+ if: steps.filter.outputs.src == 'true'
116
+ run: echo "Deploying..."
117
+
118
+ prevention:
119
+ - "Never copy `branches`, `paths`, or `tags` filters from a `push` block into a `workflow_dispatch` block."
120
+ - "Treat `workflow_dispatch` as a parameter-based trigger, not a filter-based one — use `inputs` instead."
121
+ - "If the GitHub Actions linter flags 'Unexpected value branches', remove it from the workflow_dispatch block."
122
+ - "Use the branch selector in the GitHub Actions UI for branch scoping at runtime."
123
+ docs:
124
+ - url: "https://docs.github.com/en/actions/writing-workflows/choosing-when-your-workflow-runs/events-that-trigger-workflows#workflow_dispatch"
125
+ label: "GitHub Docs: workflow_dispatch event trigger"
126
+ - url: "https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions#onpushpull_requestpull_request_targetpathspaths-ignore"
127
+ label: "GitHub Docs: paths filter (push/pull_request only)"
128
+ - url: "https://github.com/github/docs/issues/34884"
129
+ label: "github/docs#34884: documentation on workflow_dispatch is not correct/complete"
130
+ - url: "https://blog.jongallant.com/2022/04/github-actions-failing-with-unexpected-value-branches"
131
+ label: "Jon Gallant: workflow_dispatch never supported branches (2022)"
@@ -0,0 +1,136 @@
1
+ id: yaml-syntax-017
2
+ title: "Matrix include Entry Without Matching Combination Creates Unexpected Standalone Jobs"
3
+ category: yaml-syntax
4
+ severity: warning
5
+ tags:
6
+ - matrix
7
+ - include
8
+ - strategy
9
+ - extra-jobs
10
+ - standalone
11
+ - job-count
12
+ patterns:
13
+ - regex: "strategy.*matrix.*include"
14
+ flags: "i"
15
+ - regex: "matrix.*include.*extra.*job"
16
+ flags: "i"
17
+ - regex: "include.*os.*version"
18
+ flags: "i"
19
+ error_messages:
20
+ - "strategy.matrix.include"
21
+ - "unexpected job combination in matrix"
22
+ root_cause: |
23
+ GitHub Actions matrix `include` entries serve two purposes:
24
+ 1. **Add variables to existing combinations** — when the entry shares at least one
25
+ key-value pair with an existing matrix combination, it adds/overrides variables
26
+ for that specific combination only.
27
+ 2. **Create new standalone jobs** — when the entry does NOT match any existing matrix
28
+ combination, GitHub Actions treats it as an entirely NEW matrix job on its own.
29
+
30
+ This second behavior surprises developers who expect `include` to only add metadata
31
+ to existing jobs. Example that creates an unexpected extra job:
32
+
33
+ ```yaml
34
+ strategy:
35
+ matrix:
36
+ os: [ubuntu-latest, windows-latest]
37
+ node: [18, 20]
38
+ include:
39
+ - os: macos-latest # ← No matching {os: macos-latest} in matrix
40
+ node: 20
41
+ experimental: true # ← This creates a BRAND NEW 5th job, not expected
42
+ ```
43
+
44
+ The matrix produces: 4 jobs from combinations (ubuntu×18, ubuntu×20,
45
+ windows×18, windows×20) PLUS an extra 5th job for (macos-latest × 20 × experimental).
46
+
47
+ This can also cause subtle bugs when a typo in an `include` value fails to match
48
+ the existing combination, silently creating an extra duplicate-like job:
49
+
50
+ ```yaml
51
+ include:
52
+ - os: ubuntu-latest # os key matches!
53
+ node: 18
54
+ runs-long: true # Variable added to ubuntu-latest×18 job ✓
55
+ - os: ubuntu # TYPO: doesn't match "ubuntu-latest" → new standalone job ✗
56
+ node: 18
57
+ experimental: true
58
+ ```
59
+
60
+ Tracked in github/docs#23322 ("Documentation for jobs matrix strategy seems incorrect").
61
+ fix: |
62
+ **To add variables to existing combinations:** Ensure at least one key in the
63
+ `include` entry exactly matches an existing combination value. The match is
64
+ case-sensitive.
65
+
66
+ **To intentionally add a new job:** This is valid behavior — just document it clearly
67
+ in the workflow and be aware of the extra job in your branch protection rules.
68
+
69
+ **To prevent accidental extra jobs:** Review the job count after adding include entries.
70
+ The total should be: (product of all matrix dimensions) + (number of include entries
71
+ that don't match any combination).
72
+ fix_code:
73
+ - language: yaml
74
+ label: "include entry that correctly adds a variable to an existing combination"
75
+ code: |
76
+ strategy:
77
+ matrix:
78
+ os: [ubuntu-latest, windows-latest]
79
+ node: [18, 20]
80
+ include:
81
+ # This MATCHES ubuntu-latest×18 — adds 'experimental: true' to that job only
82
+ - os: ubuntu-latest # ← must exactly match the matrix value
83
+ node: 18 # ← must exactly match the matrix value
84
+ experimental: true
85
+
86
+ # This MATCHES all ubuntu-latest jobs (node 18 AND 20)
87
+ # because os key matches and node is not specified
88
+ - os: ubuntu-latest
89
+ runs-slow: true # added to ubuntu-latest×18 AND ubuntu-latest×20
90
+
91
+ - language: yaml
92
+ label: "Intentional standalone job via include (extra OS not in base matrix)"
93
+ code: |
94
+ strategy:
95
+ matrix:
96
+ os: [ubuntu-latest, windows-latest]
97
+ node: [18, 20]
98
+ include:
99
+ # Intentional extra job — macos is not in the base matrix
100
+ # Documents clearly that this creates job #5 (macos×20)
101
+ - os: macos-latest
102
+ node: 20
103
+ experimental: true
104
+ # Total jobs: 4 (base combinations) + 1 (macos standalone) = 5
105
+
106
+ - language: yaml
107
+ label: "Verify total job count matches expectations with exclude"
108
+ code: |
109
+ strategy:
110
+ matrix:
111
+ os: [ubuntu-latest, windows-latest, macos-latest]
112
+ node: [18, 20]
113
+ exclude:
114
+ # Exclude expensive macos×18 — not needed
115
+ - os: macos-latest
116
+ node: 18
117
+ include:
118
+ # Add experimental flag to ubuntu-latest×20 only
119
+ - os: ubuntu-latest
120
+ node: 20
121
+ experimental: true
122
+ # Total jobs: (3×2) - 1 excluded = 5 jobs; 0 new from include (it matches existing)
123
+
124
+ prevention:
125
+ - "Always verify the total expected job count after adding `include` entries."
126
+ - "Ensure `include` key-value pairs exactly match (case-sensitive) the base matrix values."
127
+ - "Use a comment in the workflow to document the expected total number of jobs."
128
+ - "If a typo causes an unexpected extra job, it will show up as a job with no matching `if:` context — watch for jobs that run but shouldn't."
129
+ - "Use `exclude` to remove specific combinations instead of relying solely on `include` overrides."
130
+ docs:
131
+ - url: "https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/running-variations-of-jobs-in-a-workflow#expanding-or-adding-matrix-configurations"
132
+ label: "GitHub Docs: Expanding or adding matrix configurations with include"
133
+ - url: "https://github.com/github/docs/issues/23322"
134
+ label: "github/docs#23322: Documentation for jobs matrix strategy seems incorrect"
135
+ - url: "https://stackoverflow.com/questions/78821409/github-actions-matrix-job-running-despite-false-conditions"
136
+ label: "Stack Overflow: GitHub Actions matrix job running despite false conditions"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@htekdev/actions-debugger",
3
- "version": "1.0.10",
3
+ "version": "1.0.11",
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",