@htekdev/actions-debugger 1.0.131 → 1.0.132

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,138 @@
1
+ id: concurrency-timing-061
2
+ title: '`github.workflow` in reusable workflow (`workflow_call`) returns caller''s name — shared concurrency group causes deadlock'
3
+ category: concurrency-timing
4
+ severity: error
5
+ tags:
6
+ - concurrency
7
+ - reusable-workflow
8
+ - workflow-call
9
+ - github-workflow-context
10
+ - deadlock
11
+ - concurrency-group
12
+ patterns:
13
+ - regex: 'Canceling since a deadlock for concurrency group .+ was detected between .+ and .+'
14
+ flags: 'i'
15
+ - regex: 'deadlock.*concurrency group.*detected'
16
+ flags: 'i'
17
+ error_messages:
18
+ - "Canceling since a deadlock for concurrency group 'CI-refs/heads/main' was detected between 'CI workflow' and 'deploy'"
19
+ - "Canceling since a deadlock for concurrency group 'test-refs/heads/master' was detected between 'test workflow' and 'deploy'"
20
+ root_cause: |
21
+ When a caller workflow invokes a reusable workflow via `uses:` (the `workflow_call` trigger),
22
+ the `github.workflow` context variable inside the CALLEE resolves to the CALLER's workflow
23
+ name — not the callee's own filename. This is documented behavior but it directly undermines
24
+ the widely recommended concurrency group pattern of `${{ github.workflow }}-${{ github.ref }}`.
25
+
26
+ If both the caller and the callee define:
27
+ ```yaml
28
+ concurrency:
29
+ group: ${{ github.workflow }}-${{ github.ref }}
30
+ cancel-in-progress: true
31
+ ```
32
+
33
+ Both workflows compute the SAME group key (because `github.workflow` is the caller's name in
34
+ both). GitHub detects that two workflow instances are competing for the same concurrency slot
35
+ in a way that cannot resolve — one is waiting for the other which is waiting for the first —
36
+ treats it as a deadlock, and cancels one of the runs.
37
+
38
+ **Why this is especially confusing:**
39
+ The fix recommended for general concurrency group collisions (`${{ github.workflow }}-${{ github.ref }}`)
40
+ is itself the cause of this deadlock when applied naively to reusable workflows. Teams that
41
+ copy the "safe" concurrency pattern from caller to callee introduce the bug.
42
+
43
+ **Real-world evidence:**
44
+ - actions/runner#3205: `github.workflow` returns parent workflow name in child workflows
45
+ - vergil-project/vergil-actions#176: ci-push.yml calls ci.yml via workflow_call; both use
46
+ `${{ github.workflow }}-${{ github.ref }}`; deadlock detected on every push
47
+ - github/gh-aw#35173: workflow_call fan-out cancellations due to shared concurrency namespace
48
+ - SO #78101326 (6 upvotes, 1738 views): "GitHub Actions concurrency deadlock" — 6 answers
49
+ confirming the root cause is `github.workflow` returning the caller name
50
+ fix: |
51
+ Use `github.workflow_ref` instead of `github.workflow` in the CALLEE (reusable) workflow.
52
+ `github.workflow_ref` contains the full workflow file path (e.g.
53
+ `.github/workflows/deploy.yml@refs/heads/main`), which is unique per callee file and
54
+ does NOT inherit the caller's name.
55
+
56
+ **Preferred approach:** Define concurrency ONLY in the caller workflow and remove it from the
57
+ callee entirely. The callee runs as part of the caller's run and does not need its own
58
+ concurrency group. This is the cleanest fix and matches GitHub's recommendations for
59
+ reusable workflow design.
60
+
61
+ **Avoid:** Defining concurrency in both caller and callee with the same expression — this
62
+ is the root cause of the deadlock regardless of which context variable is used for the group
63
+ key, unless the keys are guaranteed to differ.
64
+ fix_code:
65
+ - language: yaml
66
+ label: 'Callee (reusable workflow): use github.workflow_ref — unique per callee file'
67
+ code: |
68
+ # .github/workflows/deploy.yml (callee — reusable workflow)
69
+ name: Deploy
70
+
71
+ on:
72
+ workflow_call:
73
+
74
+ # ✅ github.workflow_ref includes the full path, NOT the caller's name
75
+ concurrency:
76
+ group: ${{ github.workflow_ref }}-${{ github.ref }}
77
+ cancel-in-progress: true
78
+
79
+ jobs:
80
+ deploy:
81
+ runs-on: ubuntu-latest
82
+ steps:
83
+ - uses: actions/checkout@v4
84
+ - run: ./deploy.sh
85
+ - language: yaml
86
+ label: 'Preferred: define concurrency only in the caller, none in the callee'
87
+ code: |
88
+ # .github/workflows/ci.yml (caller workflow)
89
+ name: CI
90
+
91
+ on:
92
+ push:
93
+ branches: [main]
94
+
95
+ # Concurrency defined only in the caller
96
+ concurrency:
97
+ group: ${{ github.workflow }}-${{ github.ref }}
98
+ cancel-in-progress: true
99
+
100
+ jobs:
101
+ test:
102
+ runs-on: ubuntu-latest
103
+ steps:
104
+ - run: npm test
105
+
106
+ deploy:
107
+ needs: test
108
+ # ✅ No concurrency block here — the reusable workflow has no concurrency group
109
+ uses: ./.github/workflows/deploy.yml
110
+
111
+ ---
112
+ # .github/workflows/deploy.yml (callee — reusable workflow)
113
+ name: Deploy
114
+
115
+ on:
116
+ workflow_call:
117
+
118
+ # ✅ No concurrency block — inherit scheduling from caller
119
+ jobs:
120
+ deploy:
121
+ runs-on: ubuntu-latest
122
+ steps:
123
+ - uses: actions/checkout@v4
124
+ - run: ./deploy.sh
125
+ prevention:
126
+ - "Never use `github.workflow` in a reusable workflow's concurrency group — it resolves to the caller's name, not the callee's"
127
+ - "Use `github.workflow_ref` in callee workflows if a concurrency group is truly needed there"
128
+ - "Prefer defining concurrency only in the caller when calling reusable workflows via `uses:` — keep callee stateless"
129
+ - "Audit all reusable workflows for concurrency groups that use `github.workflow` and replace with `github.workflow_ref`"
130
+ docs:
131
+ - url: 'https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/control-the-concurrency-of-workflows-and-jobs'
132
+ label: 'GitHub Docs: Control the concurrency of workflows and jobs'
133
+ - url: 'https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/accessing-contextual-information-about-workflow-runs#github-context'
134
+ label: 'GitHub Docs: github context — github.workflow_ref field'
135
+ - url: 'https://github.com/actions/runner/issues/3205'
136
+ label: 'actions/runner#3205: github.workflow returns parent name in child workflows (closed not_planned)'
137
+ - url: 'https://stackoverflow.com/questions/78101326/github-actions-concurrency-deadlock'
138
+ label: 'SO #78101326: GitHub Actions concurrency deadlock in reusable workflows (6 upvotes, 1738 views)'
@@ -0,0 +1,142 @@
1
+ id: known-unsolved-076
2
+ title: '`env` context unavailable in `strategy.matrix` — workflow env vars cannot be used in matrix definitions'
3
+ category: known-unsolved
4
+ severity: limitation
5
+ tags:
6
+ - matrix
7
+ - env-context
8
+ - strategy
9
+ - fromJSON
10
+ - dynamic-matrix
11
+ - context-availability
12
+ - known-limitation
13
+ patterns:
14
+ - regex: 'Error when evaluating .+strategy.+ for job'
15
+ flags: 'i'
16
+ - regex: 'strategy.*matrix.*\$\{\{.*env\.'
17
+ flags: 'i'
18
+ - regex: 'Unrecognized named-value: .+env.+ \(Line: \d+'
19
+ flags: 'i'
20
+ error_messages:
21
+ - "Error when evaluating 'strategy' for job 'build'. .github/workflows/deploy.yaml (Line: 10, Col: 15): Error parsing fromJson"
22
+ - "Error when evaluating 'strategy' for job 'test'. Input string '3.11' is not a valid number. Path '[0]'"
23
+ - "Error when evaluating 'strategy' for job 'matrix-job': Object reference not set to an instance of an object"
24
+ root_cause: |
25
+ The `env` context — workflow-level environment variables defined under the top-level `env:` key
26
+ — is NOT available during evaluation of `strategy.matrix`. GitHub Actions evaluates the
27
+ `strategy:` block at workflow QUEUING time, before jobs are dispatched and before environment
28
+ variable interpolation occurs. Any expression like `${{ env.VERSIONS_JSON }}` or
29
+ `${{ fromJSON(env.VERSIONS_JSON) }}` inside `strategy.matrix` resolves to an empty string
30
+ or produces a parse error.
31
+
32
+ **GitHub's documented context availability:**
33
+ Per the official context availability table, `env` is explicitly NOT listed as available in
34
+ `jobs.<job_id>.strategy`. Available contexts there are only: `github`, `inputs`, `vars`,
35
+ `needs`, `strategy`, and `matrix`.
36
+
37
+ **Common failure patterns:**
38
+ - Using `${{ fromJSON(env.MY_VERSIONS) }}` to share a JSON array between matrix and other steps
39
+ - Setting `env: DEPLOY_ENVS: '["staging","production"]'` at workflow level and referencing it
40
+ in the matrix include/exclude blocks
41
+ - Using workflow-level env vars to DRY up matrix configs shared with `run:` script logic
42
+
43
+ **Why this surprises developers:**
44
+ - `env` IS available inside `jobs.<job_id>.steps.*` — the limitation is specific to `strategy`
45
+ - The error message "Error parsing fromJson" doesn't mention that `env` context is unavailable
46
+ - The empty-string resolution (when no parse error) causes a silent empty matrix, not an error
47
+
48
+ Sources: actions/runner#480 (281 👍, open since 2020 — most-upvoted env context limitation);
49
+ SO#74072206 (10 upvotes, 19,053 views); SO#76039616 (6 upvotes, 10,482 views)
50
+ fix: |
51
+ Three workarounds exist, in order of preference:
52
+
53
+ **Option 1 — Use `vars` context (org/repo-level variables)**
54
+ Org-level and repo-level variables (`vars.*`) ARE available in `strategy.matrix`.
55
+ Move shared values to repository Settings → Secrets and variables → Variables instead of
56
+ workflow-level `env:`.
57
+
58
+ **Option 2 — Compute matrix in a previous job's output (most flexible)**
59
+ Use a dedicated setup job that outputs the matrix JSON, then reference it in dependent
60
+ jobs via `fromJSON(needs.setup.outputs.matrix)`. This also enables dynamic matrix
61
+ generation from files, APIs, or scripts.
62
+
63
+ **Option 3 — Hardcode values directly in strategy.matrix**
64
+ Duplicate the values in `strategy.matrix` explicitly. Avoids the DRY violation but
65
+ is the simplest fix when values rarely change.
66
+ fix_code:
67
+ - language: yaml
68
+ label: 'Option 1: Use vars context — repo/org variables ARE available in strategy'
69
+ code: |
70
+ # In repo Settings → Secrets and variables → Variables, create:
71
+ # Name: PYTHON_VERSIONS Value: ["3.10","3.11","3.12"]
72
+
73
+ jobs:
74
+ test:
75
+ strategy:
76
+ matrix:
77
+ # ✅ vars context IS available in strategy.matrix
78
+ python-version: ${{ fromJSON(vars.PYTHON_VERSIONS) }}
79
+ runs-on: ubuntu-latest
80
+ steps:
81
+ - uses: actions/setup-python@v5
82
+ with:
83
+ python-version: ${{ matrix.python-version }}
84
+ - run: python -m pytest
85
+ - language: yaml
86
+ label: 'Option 2: Compute matrix in a setup job, pass via needs outputs'
87
+ code: |
88
+ jobs:
89
+ setup:
90
+ runs-on: ubuntu-latest
91
+ outputs:
92
+ matrix: ${{ steps.set-matrix.outputs.matrix }}
93
+ steps:
94
+ - id: set-matrix
95
+ run: |
96
+ # Build matrix from any source: env var, file, API, conditional logic
97
+ echo 'matrix={"python-version":["3.10","3.11","3.12"]}' >> "$GITHUB_OUTPUT"
98
+
99
+ test:
100
+ needs: setup
101
+ strategy:
102
+ matrix:
103
+ # ✅ fromJSON(needs.*.outputs.*) IS available in strategy.matrix
104
+ ${{ fromJSON(needs.setup.outputs.matrix) }}
105
+ runs-on: ubuntu-latest
106
+ steps:
107
+ - uses: actions/setup-python@v5
108
+ with:
109
+ python-version: ${{ matrix.python-version }}
110
+ - run: python -m pytest
111
+ - language: yaml
112
+ label: 'Anti-pattern: env context in strategy.matrix causes parse error'
113
+ code: |
114
+ # ❌ Workflow-level env vars are NOT available in strategy.matrix
115
+
116
+ env:
117
+ PYTHON_VERSIONS: '["3.10","3.11","3.12"]'
118
+
119
+ jobs:
120
+ test:
121
+ strategy:
122
+ matrix:
123
+ # This causes: "Error when evaluating 'strategy' for job 'test'"
124
+ python-version: ${{ fromJSON(env.PYTHON_VERSIONS) }}
125
+ runs-on: ubuntu-latest
126
+ steps:
127
+ - run: python --version
128
+ prevention:
129
+ - "Use `vars.*` (repo/org variables from Settings) instead of workflow `env:` for values shared between matrix and steps"
130
+ - "Generate dynamic matrices in a dedicated setup job and pass via `needs.*.outputs.*`"
131
+ - "Consult the GitHub Actions context availability table before using any context in `strategy` — not all contexts are available there"
132
+ - "actionlint will flag `env` context usage in strategy blocks — add it to your CI pipeline or pre-commit hooks"
133
+ - "Remember: `env` IS available in `steps.*.run`, `steps.*.with`, and most other places — the restriction is specific to `strategy` and `concurrency`"
134
+ docs:
135
+ - url: 'https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/accessing-contextual-information-about-workflow-runs#context-availability'
136
+ label: 'GitHub Docs: Context availability table (env not listed for strategy)'
137
+ - url: 'https://github.com/actions/runner/issues/480'
138
+ label: 'actions/runner#480: Workflow level env does not work in all fields (281 upvotes, open since 2020)'
139
+ - url: 'https://stackoverflow.com/questions/74072206/github-actions-use-variables-in-matrix-definition'
140
+ label: 'SO #74072206: Use variables in matrix definition (10 upvotes, 19,053 views)'
141
+ - url: 'https://stackoverflow.com/questions/76039616/how-to-read-in-an-array-of-strings-to-matrix-in-github-actions'
142
+ label: 'SO #76039616: Read array of strings into matrix (6 upvotes, 10,482 views)'
@@ -0,0 +1,140 @@
1
+ id: silent-failures-121
2
+ title: '`workflow_run: types: [completed]` triggers on ALL conclusions — deploy runs even when CI failed or was cancelled'
3
+ category: silent-failures
4
+ severity: silent-failure
5
+ tags:
6
+ - workflow-run
7
+ - conclusion
8
+ - silent-failure
9
+ - deploy-on-failure
10
+ - ci-cd
11
+ - workflow-trigger
12
+ - conclusion-check
13
+ patterns:
14
+ - regex: 'on:\s*\n\s+workflow_run:'
15
+ flags: 'im'
16
+ - regex: 'types:\s*[\[\s]*completed[\]\s]*\n'
17
+ flags: 'i'
18
+ error_messages:
19
+ - "# No error message — the deploy workflow runs silently even when upstream CI failed or was cancelled"
20
+ root_cause: |
21
+ The `workflow_run` event with `types: [completed]` fires whenever the referenced workflow
22
+ finishes — regardless of its conclusion. A completed workflow can have any of these conclusions:
23
+ `success`, `failure`, `cancelled`, `skipped`, `timed_out`, `action_required`, `neutral`,
24
+ or `stale`. GitHub fires `workflow_run: completed` for ALL of these states.
25
+
26
+ Developers commonly use `workflow_run` to chain a deploy or release workflow after a CI
27
+ workflow passes. The intuitive reading of "completed" is "finished successfully," but GitHub's
28
+ semantics are "finished with any outcome":
29
+
30
+ ```yaml
31
+ # ❌ This runs deploy even when CI failed, was cancelled, or was skipped
32
+ on:
33
+ workflow_run:
34
+ workflows: [CI]
35
+ types: [completed]
36
+ ```
37
+
38
+ Without an explicit `if:` conclusion check, the deploy workflow runs unconditionally after CI —
39
+ including when CI failed mid-run, was cancelled by a force-push, or was skipped by a path
40
+ filter. This silently deploys broken code (or publishes, releases, or notifies) whenever CI
41
+ does not succeed.
42
+
43
+ **Why this is a silent failure:**
44
+ - No error appears — the triggered workflow runs normally and reports "success"
45
+ - The CI failure and deploy completion appear as separate workflow runs — easy to miss
46
+ - GitHub does not add a default conclusion filter — the developer must add it manually
47
+ - The mistake is natural: "trigger when CI is done" sounds equivalent to "trigger when CI passes"
48
+
49
+ Sources: GitHub Docs (workflow_run event, conclusion field); SO#62750603 (159 upvotes,
50
+ 152,034 views — top answer recommends adding conclusion check); `ahmadnassri/action-workflow-run-wait`
51
+ (39 stars — third-party action created specifically to work around this limitation)
52
+ fix: |
53
+ Add an `if:` condition at the JOB level (not workflow level) to check
54
+ `github.event.workflow_run.conclusion == 'success'`. Job-level conditions are evaluated at
55
+ runtime after the event fires, so this reliably gates deployment on CI success.
56
+
57
+ Do NOT put the `if:` check at the workflow level — it prevents ALL jobs from running,
58
+ including any cleanup or notification jobs that should run regardless of conclusion.
59
+
60
+ For workflows that need to handle both success and failure (e.g., notify Slack of failures),
61
+ use separate jobs with different `if:` checks.
62
+ fix_code:
63
+ - language: yaml
64
+ label: 'Add conclusion check at the job level — most common fix'
65
+ code: |
66
+ name: Deploy
67
+
68
+ on:
69
+ workflow_run:
70
+ workflows: [CI]
71
+ types: [completed]
72
+
73
+ jobs:
74
+ deploy:
75
+ # ✅ Only deploy when CI succeeded
76
+ if: github.event.workflow_run.conclusion == 'success'
77
+ runs-on: ubuntu-latest
78
+ steps:
79
+ - uses: actions/checkout@v4
80
+ with:
81
+ # workflow_run always checks out default branch — use ref for PR branches
82
+ ref: ${{ github.event.workflow_run.head_sha }}
83
+ - run: ./deploy.sh
84
+ - language: yaml
85
+ label: 'Branch by conclusion — deploy on success, notify on failure'
86
+ code: |
87
+ name: Post-CI Actions
88
+
89
+ on:
90
+ workflow_run:
91
+ workflows: [CI]
92
+ types: [completed]
93
+
94
+ jobs:
95
+ deploy:
96
+ if: github.event.workflow_run.conclusion == 'success'
97
+ runs-on: ubuntu-latest
98
+ steps:
99
+ - run: ./deploy.sh
100
+
101
+ notify-failure:
102
+ if: >-
103
+ github.event.workflow_run.conclusion == 'failure' ||
104
+ github.event.workflow_run.conclusion == 'timed_out'
105
+ runs-on: ubuntu-latest
106
+ steps:
107
+ - name: Notify team of CI failure
108
+ run: |
109
+ echo "CI failed on branch ${{ github.event.workflow_run.head_branch }}"
110
+ # Send Slack/Teams notification here
111
+ - language: yaml
112
+ label: 'Anti-pattern: missing conclusion check silently deploys broken code'
113
+ code: |
114
+ # ❌ BAD: Runs even when CI failed, was cancelled, or was skipped by path filter
115
+ on:
116
+ workflow_run:
117
+ workflows: [CI]
118
+ types: [completed] # "completed" means ANY outcome, not just success
119
+
120
+ jobs:
121
+ deploy:
122
+ # No if: conclusion check — deploys broken code on CI failure!
123
+ runs-on: ubuntu-latest
124
+ steps:
125
+ - run: ./deploy.sh
126
+ prevention:
127
+ - "Always add `if: github.event.workflow_run.conclusion == 'success'` to deploy/release jobs triggered by workflow_run"
128
+ - "Remember: 'completed' means the upstream workflow finished — NOT that it succeeded; always check conclusion explicitly"
129
+ - "Use separate jobs with different `if: conclusion ==` checks for success vs failure vs cancelled handling"
130
+ - "Consider adding a linting step or actionlint check that flags workflow_run jobs without a conclusion check"
131
+ - "Test the failure path by intentionally failing CI and verifying the downstream workflow does NOT deploy"
132
+ docs:
133
+ - url: 'https://docs.github.com/en/actions/writing-workflows/choosing-when-your-workflow-runs/events-that-trigger-workflows#workflow_run'
134
+ label: 'GitHub Docs: workflow_run event — conclusion field and types'
135
+ - url: 'https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/accessing-contextual-information-about-workflow-runs#github-context'
136
+ label: 'GitHub Docs: github.event.workflow_run context properties'
137
+ - url: 'https://stackoverflow.com/questions/62750603/github-actions-trigger-another-action-after-one-action-is-completed'
138
+ label: 'SO #62750603: Trigger action after completion — top answer adds conclusion check (159 upvotes, 152k views)'
139
+ - url: 'https://github.com/ahmadnassri/action-workflow-run-wait'
140
+ label: 'ahmadnassri/action-workflow-run-wait — third-party action created to wait for successful workflow_run'
@@ -0,0 +1,142 @@
1
+ id: triggers-074
2
+ title: '`workflow_run: branches:` filter silently never triggers when upstream was started by `schedule` or `workflow_dispatch` — `head_branch` is null'
3
+ category: triggers
4
+ severity: silent-failure
5
+ tags:
6
+ - workflow-run
7
+ - branches-filter
8
+ - head-branch
9
+ - schedule
10
+ - workflow-dispatch
11
+ - null
12
+ - silent-failure
13
+ - trigger-missing
14
+ patterns:
15
+ - regex: 'on:\s*\n\s+workflow_run:\s*\n(.|\n)*?branches:\s*\n'
16
+ flags: 'im'
17
+ - regex: 'workflow_run.*branches.*schedule\s*$|schedule.*workflow_run.*branches'
18
+ flags: 'im'
19
+ error_messages:
20
+ - "# No error message — the downstream workflow simply never runs when upstream was triggered by schedule or workflow_dispatch"
21
+ root_cause: |
22
+ The `workflow_run` event exposes a `branches:` filter that is supposed to limit which upstream
23
+ workflow run conclusions trigger the downstream workflow. The filter compares against
24
+ `github.event.workflow_run.head_branch`.
25
+
26
+ **The problem:** When the upstream workflow is triggered by a `schedule` or `workflow_dispatch`
27
+ event, GitHub sets `head_branch` to `null` (not a branch name). The `branches:` filter then
28
+ evaluates `null` against each pattern in the list — and null never matches any branch name
29
+ pattern, including `[main]`, `['**']`, or any glob. The downstream workflow silently never
30
+ triggers, even though the upstream ran successfully on main.
31
+
32
+ **Event types that produce null head_branch:**
33
+ - `schedule` — cron-triggered workflows have no associated branch context
34
+ - `workflow_dispatch` — manually dispatched workflows MAY have null head_branch in some cases
35
+
36
+ **Pull request triggers correctly populate head_branch** (the PR head branch name), and
37
+ `push` triggers also correctly populate it (the pushed branch name). The null behavior is
38
+ specific to schedule and dispatch events on the upstream.
39
+
40
+ **Why this is a silent failure:**
41
+ - No error is raised — the downstream workflow simply does not appear in the Actions UI for that run
42
+ - The upstream workflow runs and completes successfully
43
+ - The `branches:` filter looks correct — `[main]` is the right branch name
44
+ - The issue only manifests for schedule/dispatch-triggered upstream runs; if CI also triggers
45
+ on push to main, push-triggered runs DO reach the downstream workflow
46
+
47
+ **Example scenario:** A deploy workflow runs after CI. CI has `on: [push, schedule]`.
48
+ The `branches: [main]` filter in the deploy's workflow_run block works for push events but
49
+ silently skips all scheduled CI runs.
50
+
51
+ Sources: GitHub Docs (workflow_run, head_branch null for schedule); community/discussions
52
+ related to workflow_run not triggering after schedule; documented in
53
+ `workflow-run-head-branch-null-schedule-dispatch-concurrency.yml` (concurrency variant)
54
+ fix: |
55
+ Remove the `branches:` filter from the `workflow_run` trigger entirely and instead use a
56
+ job-level `if:` condition to check the branch after the event fires. The `if:` condition
57
+ evaluates at runtime and can handle null gracefully.
58
+
59
+ For schedule-triggered upstreams, use `github.event.workflow_run.head_branch == 'main' ||
60
+ github.event.workflow_run.head_branch == null` (null means it ran from the default branch).
61
+
62
+ Alternatively, filter by the workflow run's `head_sha` and check against known branch SHAs.
63
+ fix_code:
64
+ - language: yaml
65
+ label: 'Remove branches filter and add job-level if condition — handles schedule and dispatch'
66
+ code: |
67
+ name: Deploy After CI
68
+
69
+ on:
70
+ workflow_run:
71
+ workflows: [CI]
72
+ types: [completed]
73
+ # ❌ Do NOT use branches: here if CI runs on schedule or workflow_dispatch
74
+ # branches: [main] # This silently skips all schedule-triggered CI runs
75
+
76
+ jobs:
77
+ deploy:
78
+ # ✅ Use job-level if: instead of trigger-level branches:
79
+ # null head_branch means schedule/dispatch from default branch — include it
80
+ if: >-
81
+ github.event.workflow_run.conclusion == 'success' &&
82
+ (github.event.workflow_run.head_branch == 'main' ||
83
+ github.event.workflow_run.head_branch == null)
84
+ runs-on: ubuntu-latest
85
+ steps:
86
+ - uses: actions/checkout@v4
87
+ - run: ./deploy.sh
88
+ - language: yaml
89
+ label: 'When upstream is push-only: branches filter works fine (head_branch is always set)'
90
+ code: |
91
+ name: Deploy After CI (push-only upstream)
92
+
93
+ on:
94
+ workflow_run:
95
+ workflows: [CI]
96
+ types: [completed]
97
+ # ✅ branches: filter works correctly ONLY when upstream runs on push or pull_request
98
+ # Because push and pull_request events always set head_branch
99
+ branches: [main]
100
+
101
+ jobs:
102
+ deploy:
103
+ if: github.event.workflow_run.conclusion == 'success'
104
+ runs-on: ubuntu-latest
105
+ steps:
106
+ - uses: actions/checkout@v4
107
+ - run: ./deploy.sh
108
+
109
+ # ⚠️ If CI also has on: schedule — add null check above or remove branches: filter
110
+ - language: yaml
111
+ label: 'Anti-pattern: branches filter with schedule-triggered upstream — downstream never fires'
112
+ code: |
113
+ # ❌ BAD: Upstream CI has on: [push, schedule]
114
+ # But deploy's branches filter silently skips all scheduled CI runs
115
+
116
+ name: Deploy After CI
117
+
118
+ on:
119
+ workflow_run:
120
+ workflows: [CI]
121
+ types: [completed]
122
+ branches: [main] # null (from schedule) never matches 'main' — deploy skipped!
123
+
124
+ jobs:
125
+ deploy:
126
+ if: github.event.workflow_run.conclusion == 'success'
127
+ runs-on: ubuntu-latest
128
+ steps:
129
+ - run: ./deploy.sh # Never runs after scheduled CI
130
+ prevention:
131
+ - "Avoid `branches:` filter in workflow_run if the upstream workflow can be triggered by `schedule` or `workflow_dispatch`"
132
+ - "Use job-level `if:` conditions with explicit null handling instead of trigger-level branch filters"
133
+ - "Check the upstream workflow's triggers — if it includes `schedule` or `workflow_dispatch`, `head_branch` will be null for those runs"
134
+ - "Test by triggering the upstream workflow manually and verifying the downstream workflow appears in the Actions UI"
135
+ - "When null head_branch is acceptable (schedule from default branch), use `head_branch == 'main' || head_branch == null`"
136
+ docs:
137
+ - url: 'https://docs.github.com/en/actions/writing-workflows/choosing-when-your-workflow-runs/events-that-trigger-workflows#workflow_run'
138
+ label: 'GitHub Docs: workflow_run event — branches filter and head_branch field'
139
+ - url: 'https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/accessing-contextual-information-about-workflow-runs#github-context'
140
+ label: 'GitHub Docs: github.event.workflow_run — head_branch property (null for schedule/dispatch)'
141
+ - url: 'https://github.com/orgs/community/discussions/26238'
142
+ label: 'GitHub Community: workflow_run not triggering — head_branch null discussion'
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@htekdev/actions-debugger",
3
- "version": "1.0.131",
3
+ "version": "1.0.132",
4
4
  "description": "65+ real GitHub Actions errors, queryable by agents. CLI + MCP server + Copilot skills + error database.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",