@htekdev/actions-debugger 1.0.133 → 1.0.135
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.
- package/errors/known-unsolved/known-unsolved-078.yml +91 -0
- package/errors/runner-environment/runner-environment-247.yml +73 -0
- package/errors/runner-environment/runner-environment-248.yml +106 -0
- package/errors/runner-environment/runner-environment-249.yml +144 -0
- package/errors/silent-failures/silent-failures-122.yml +102 -0
- package/errors/yaml-syntax/yaml-syntax-078.yml +125 -0
- package/errors/yaml-syntax/yaml-syntax-079.yml +148 -0
- package/package.json +1 -1
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
id: known-unsolved-078
|
|
2
|
+
title: 'Copilot agent branches not available in `workflow_dispatch` branch picker — cannot manually target Copilot branches'
|
|
3
|
+
category: known-unsolved
|
|
4
|
+
severity: limitation
|
|
5
|
+
tags:
|
|
6
|
+
- workflow_dispatch
|
|
7
|
+
- copilot-agent
|
|
8
|
+
- branch-picker
|
|
9
|
+
- manual-trigger
|
|
10
|
+
- github-copilot
|
|
11
|
+
- ui-limitation
|
|
12
|
+
patterns:
|
|
13
|
+
- regex: 'copilot.*branch.*not.*available|copilot.*branch.*missing.*dispatch'
|
|
14
|
+
flags: 'i'
|
|
15
|
+
- regex: 'workflow_dispatch.*copilot.*branch|copilot.*agent.*branch.*trigger'
|
|
16
|
+
flags: 'i'
|
|
17
|
+
error_messages:
|
|
18
|
+
- "# No error message — Copilot agent branches simply do not appear in the branch selector"
|
|
19
|
+
root_cause: |
|
|
20
|
+
When GitHub Copilot coding agent creates a branch to work on an assigned task,
|
|
21
|
+
the branch uses a namespaced prefix (`copilot/` by default, e.g.,
|
|
22
|
+
`copilot/fix-issue-123`). These branches are created and owned by the Copilot agent.
|
|
23
|
+
|
|
24
|
+
The GitHub Actions UI for `workflow_dispatch` presents a branch picker dropdown
|
|
25
|
+
that allows users to select which branch to run the workflow against. However,
|
|
26
|
+
Copilot agent branches are NOT included in this branch picker.
|
|
27
|
+
|
|
28
|
+
This is a UI-level platform limitation: GitHub filters the branch list shown in the
|
|
29
|
+
`workflow_dispatch` selector and excludes Copilot-owned branches from the list.
|
|
30
|
+
There is no documented API reason why this would be necessary — the branches exist
|
|
31
|
+
and are valid git refs — but the UI omits them.
|
|
32
|
+
|
|
33
|
+
As a workaround, the GitHub CLI or REST API CAN be used to trigger a
|
|
34
|
+
`workflow_dispatch` run targeting a Copilot branch by supplying the `ref` parameter
|
|
35
|
+
explicitly (bypassing the UI picker).
|
|
36
|
+
|
|
37
|
+
This issue was reported in runner#4246 (Feb 2026, 15 reactions) and remained open
|
|
38
|
+
as of June 2026. No ETA for a fix has been provided.
|
|
39
|
+
|
|
40
|
+
Note: This is a separate issue from Copilot agent PR workflows requiring approval
|
|
41
|
+
before running (triggers-027). That entry covers automatic workflows on Copilot PRs;
|
|
42
|
+
this entry covers the inability to manually dispatch TO a Copilot branch via the UI.
|
|
43
|
+
fix: |
|
|
44
|
+
There is no UI fix — Copilot agent branches cannot be selected in the GitHub Actions
|
|
45
|
+
web interface workflow_dispatch branch picker.
|
|
46
|
+
|
|
47
|
+
**Workaround: use the GitHub CLI to trigger workflow_dispatch with an explicit ref:**
|
|
48
|
+
```bash
|
|
49
|
+
gh workflow run <workflow-file.yml> --ref copilot/fix-issue-123
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
**Workaround: use the GitHub REST API:**
|
|
53
|
+
```bash
|
|
54
|
+
curl -X POST \
|
|
55
|
+
-H "Authorization: Bearer $GITHUB_TOKEN" \
|
|
56
|
+
-H "Accept: application/vnd.github+json" \
|
|
57
|
+
https://api.github.com/repos/{owner}/{repo}/actions/workflows/{workflow_id}/dispatches \
|
|
58
|
+
-d '{"ref":"copilot/fix-issue-123","inputs":{}}'
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Both the CLI and API accept any valid branch ref, including Copilot branches,
|
|
62
|
+
even though the UI does not display them.
|
|
63
|
+
fix_code:
|
|
64
|
+
- language: yaml
|
|
65
|
+
label: "Trigger workflow_dispatch on a Copilot branch via GitHub CLI (run from local terminal or another workflow)"
|
|
66
|
+
code: |
|
|
67
|
+
# Run locally or in a helper workflow step:
|
|
68
|
+
# gh workflow run deploy.yml --ref copilot/fix-issue-123
|
|
69
|
+
|
|
70
|
+
# Or call via the REST API in a workflow step:
|
|
71
|
+
- name: Dispatch workflow on Copilot branch
|
|
72
|
+
run: |
|
|
73
|
+
gh workflow run deploy.yml \
|
|
74
|
+
--ref "${{ github.head_ref }}" \
|
|
75
|
+
--repo ${{ github.repository }}
|
|
76
|
+
env:
|
|
77
|
+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
78
|
+
prevention:
|
|
79
|
+
- "Use the GitHub CLI (gh workflow run --ref <branch>) instead of the UI when targeting Copilot branches"
|
|
80
|
+
- "Use the REST API dispatches endpoint with an explicit ref to trigger workflows on any branch"
|
|
81
|
+
- "Follow runner#4246 for updates on when UI support for Copilot branches may be added"
|
|
82
|
+
- "Build automation that runs in workflow_run triggered by the Copilot branch's push event instead of requiring manual dispatch"
|
|
83
|
+
docs:
|
|
84
|
+
- url: "https://github.com/actions/runner/issues/4246"
|
|
85
|
+
label: "runner#4246 — Cannot trigger workflows manually targeting a copilot agent branch (Feb 2026, 15 reactions)"
|
|
86
|
+
- url: "https://cli.github.com/manual/gh_workflow_run"
|
|
87
|
+
label: "GitHub CLI — gh workflow run (supports --ref for any branch)"
|
|
88
|
+
- url: "https://docs.github.com/en/rest/actions/workflows?apiVersion=2022-11-28#create-a-workflow-dispatch-event"
|
|
89
|
+
label: "GitHub REST API — Create a workflow dispatch event (accepts any ref)"
|
|
90
|
+
- url: "https://docs.github.com/en/copilot/using-github-copilot/using-copilot-coding-agent-in-github"
|
|
91
|
+
label: "GitHub Docs — Using Copilot coding agent"
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
id: runner-environment-247
|
|
2
|
+
title: '`apt-get install` stalls ~75 seconds on ubuntu-24.04 — "Processing triggers for man-db" post-install hook'
|
|
3
|
+
category: runner-environment
|
|
4
|
+
severity: warning
|
|
5
|
+
tags:
|
|
6
|
+
- ubuntu-24.04
|
|
7
|
+
- apt-get
|
|
8
|
+
- man-db
|
|
9
|
+
- package-install
|
|
10
|
+
- performance
|
|
11
|
+
- slow
|
|
12
|
+
patterns:
|
|
13
|
+
- regex: 'Processing triggers for man-db \('
|
|
14
|
+
flags: 'i'
|
|
15
|
+
- regex: 'man-db.*stall|stall.*man-db'
|
|
16
|
+
flags: 'i'
|
|
17
|
+
error_messages:
|
|
18
|
+
- "Processing triggers for man-db (2.12.0-4build2) ..."
|
|
19
|
+
- "Processing triggers for man-db (2.12.0-4build2) ..."
|
|
20
|
+
root_cause: |
|
|
21
|
+
On ubuntu-24.04 runners, installing any package that triggers the `man-db` post-install
|
|
22
|
+
hook causes a ~75-second stall during the `apt-get install` step.
|
|
23
|
+
|
|
24
|
+
The `man-db` daemon (which indexes manual pages for `man` lookups) has a post-install
|
|
25
|
+
trigger that runs `mandb` to rebuild the manual page database after packages are
|
|
26
|
+
installed. On ubuntu-24.04, this database rebuild operation runs synchronously and
|
|
27
|
+
takes approximately 60-90 seconds, blocking the apt post-install phase.
|
|
28
|
+
|
|
29
|
+
Any package that installs manual pages (cmake, make, build-essential, gcc, etc.)
|
|
30
|
+
triggers this slow hook. Workflows that install multiple packages in a single
|
|
31
|
+
`apt-get install` step will still only pay the cost once (one rebuild per transaction),
|
|
32
|
+
but even a single apt install with man pages will stall for over a minute.
|
|
33
|
+
|
|
34
|
+
The `man-db` package is installed by default on ubuntu-24.04 runner images. This
|
|
35
|
+
issue was reported in September 2025 and remains open as of June 2026 (runner#4030).
|
|
36
|
+
fix: |
|
|
37
|
+
Option 1 — Remove man-db before running apt-get install commands:
|
|
38
|
+
```yaml
|
|
39
|
+
- name: Remove man-db to prevent slow post-install trigger
|
|
40
|
+
run: sudo apt-get remove --purge -y man-db
|
|
41
|
+
```
|
|
42
|
+
After removing man-db, all subsequent apt installs skip the man page indexing trigger.
|
|
43
|
+
|
|
44
|
+
Option 2 — Disable the man-db auto-update file (lighter weight):
|
|
45
|
+
```yaml
|
|
46
|
+
- name: Disable man-db auto-update
|
|
47
|
+
run: sudo rm -f /var/lib/man-db/auto-update
|
|
48
|
+
```
|
|
49
|
+
This deletes the sentinel file that triggers auto-update, preventing the stall without
|
|
50
|
+
uninstalling man-db.
|
|
51
|
+
|
|
52
|
+
Option 3 — Set DEBIAN_FRONTEND and skip recommended packages (partial mitigation):
|
|
53
|
+
Some packages still trigger man-db via direct page installation, but combining
|
|
54
|
+
`--no-install-recommends` reduces the set of affected packages.
|
|
55
|
+
fix_code:
|
|
56
|
+
- language: yaml
|
|
57
|
+
label: "Remove man-db before apt-get installs to eliminate the stall"
|
|
58
|
+
code: |
|
|
59
|
+
- name: Remove man-db (prevents ~75s stall on ubuntu-24.04)
|
|
60
|
+
run: sudo apt-get remove --purge -y man-db
|
|
61
|
+
|
|
62
|
+
- name: Install dependencies
|
|
63
|
+
run: sudo apt-get install -y cmake make build-essential
|
|
64
|
+
prevention:
|
|
65
|
+
- "Remove or disable man-db at the start of jobs that run apt-get install on ubuntu-24.04"
|
|
66
|
+
- "Use sudo rm -f /var/lib/man-db/auto-update as a lighter-weight alternative to removing the package"
|
|
67
|
+
- "Combine all apt-get installs into a single command to pay the man-db trigger cost only once"
|
|
68
|
+
- "Monitor job timing — if an apt step takes 75+ extra seconds on ubuntu-24.04, man-db is the cause"
|
|
69
|
+
docs:
|
|
70
|
+
- url: "https://github.com/actions/runner/issues/4030"
|
|
71
|
+
label: "GitHub runner#4030 — man-db trigger severely stalls package installation on ubuntu-24.04"
|
|
72
|
+
- url: "https://manpages.ubuntu.com/manpages/noble/man8/mandb.8.html"
|
|
73
|
+
label: "Ubuntu mandb(8) manual — man page database indexer"
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
id: runner-environment-248
|
|
2
|
+
title: '`actions/checkout` causes "Duplicate header: Authorization" — git returns 400 on subsequent git operations'
|
|
3
|
+
category: runner-environment
|
|
4
|
+
severity: error
|
|
5
|
+
tags:
|
|
6
|
+
- checkout
|
|
7
|
+
- git
|
|
8
|
+
- authorization
|
|
9
|
+
- http-extraheader
|
|
10
|
+
- credentials
|
|
11
|
+
- 400
|
|
12
|
+
- duplicate-header
|
|
13
|
+
patterns:
|
|
14
|
+
- regex: 'Duplicate header.*Authorization|remote.*Duplicate header.*Authorization'
|
|
15
|
+
flags: 'i'
|
|
16
|
+
- regex: 'fatal.*unable to access.*The requested URL returned error: 400'
|
|
17
|
+
flags: 'i'
|
|
18
|
+
- regex: 'http\.extraheader.*AUTHORIZATION.*duplicate|duplicate.*AUTHORIZATION.*extraheader'
|
|
19
|
+
flags: 'i'
|
|
20
|
+
error_messages:
|
|
21
|
+
- "remote: Duplicate header: \"Authorization\""
|
|
22
|
+
- "fatal: unable to access 'https://github.com/org/repo/': The requested URL returned error: 400"
|
|
23
|
+
- "Error: The process '/usr/bin/git' failed with exit code 128"
|
|
24
|
+
root_cause: |
|
|
25
|
+
When `actions/checkout` runs, it configures git credentials by setting an
|
|
26
|
+
`http.extraheader` entry containing an `AUTHORIZATION: bearer <token>` header.
|
|
27
|
+
This header is added to git's global or repository-level config so that all
|
|
28
|
+
subsequent git operations over HTTPS are authenticated.
|
|
29
|
+
|
|
30
|
+
The "Duplicate header: Authorization" error occurs when a second Authorization
|
|
31
|
+
header is injected on top of the one already set by checkout. This can happen in
|
|
32
|
+
two scenarios:
|
|
33
|
+
|
|
34
|
+
1. **Pin to @main or an unstable tag**: Using `actions/checkout@main` (or any
|
|
35
|
+
edge/pre-release revision) picks up unreleased changes that may change the
|
|
36
|
+
credential injection mechanism. In some checkout versions, the http.extraheader
|
|
37
|
+
is written in a way that stacks with git's built-in credential manager, sending
|
|
38
|
+
two conflicting Authorization headers in the same HTTP request.
|
|
39
|
+
|
|
40
|
+
2. **Multiple checkout calls with persist-credentials: true** (the default):
|
|
41
|
+
The first checkout sets the global http.extraheader. A second checkout step
|
|
42
|
+
(e.g., checking out a second repository) may add a new header without first
|
|
43
|
+
removing the existing one, depending on the git version and checkout version.
|
|
44
|
+
|
|
45
|
+
GitHub's servers reject HTTP requests with two Authorization headers with HTTP 400,
|
|
46
|
+
returning "Duplicate header: Authorization" in the response. Git then reports
|
|
47
|
+
`fatal: unable to access ... The requested URL returned error: 400`.
|
|
48
|
+
|
|
49
|
+
The bug was reported in checkout#2299 (Nov 2025, 10 reactions) and checkout#2215
|
|
50
|
+
(Jul 2025, 8 reactions) and remained open as of June 2026.
|
|
51
|
+
fix: |
|
|
52
|
+
Option 1 — Pin to a stable released version tag instead of @main:
|
|
53
|
+
Replace `actions/checkout@main` with a specific release tag (e.g.,
|
|
54
|
+
`actions/checkout@v4` or `actions/checkout@v4.2.2`). The stable release series
|
|
55
|
+
has known credential injection behaviour that does not produce duplicate headers.
|
|
56
|
+
|
|
57
|
+
Option 2 — Clear http.extraheader between checkout steps:
|
|
58
|
+
If you must run multiple checkout steps, add a step between them to clear the
|
|
59
|
+
credential header before the second checkout:
|
|
60
|
+
```yaml
|
|
61
|
+
- name: Clear git credentials before second checkout
|
|
62
|
+
run: git config --global --unset-all http.extraheader || true
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Option 3 — Use token: input only on the checkout that needs it and set
|
|
66
|
+
persist-credentials: false on checkouts that do not need to push:
|
|
67
|
+
```yaml
|
|
68
|
+
- uses: actions/checkout@v4
|
|
69
|
+
with:
|
|
70
|
+
persist-credentials: false
|
|
71
|
+
```
|
|
72
|
+
fix_code:
|
|
73
|
+
- language: yaml
|
|
74
|
+
label: "Pin to stable checkout version to avoid duplicate header bug"
|
|
75
|
+
code: |
|
|
76
|
+
- name: Checkout repository
|
|
77
|
+
uses: actions/checkout@v4 # Pin to stable tag, NOT @main
|
|
78
|
+
with:
|
|
79
|
+
fetch-depth: 0
|
|
80
|
+
|
|
81
|
+
- language: yaml
|
|
82
|
+
label: "Clear git extraheader between multiple checkout steps"
|
|
83
|
+
code: |
|
|
84
|
+
- uses: actions/checkout@v4
|
|
85
|
+
with:
|
|
86
|
+
repository: org/first-repo
|
|
87
|
+
|
|
88
|
+
- name: Clear git credentials
|
|
89
|
+
run: git config --global --unset-all http.extraheader || true
|
|
90
|
+
|
|
91
|
+
- uses: actions/checkout@v4
|
|
92
|
+
with:
|
|
93
|
+
repository: org/second-repo
|
|
94
|
+
path: second-repo
|
|
95
|
+
prevention:
|
|
96
|
+
- "Never pin actions to @main or mutable tags — always use immutable version tags (e.g., @v4 or @v4.2.2)"
|
|
97
|
+
- "If using multiple checkout steps, set persist-credentials: false on steps that don't require pushing"
|
|
98
|
+
- "Check git config --global --list | grep extraheader if unexpected 400 errors occur on git operations"
|
|
99
|
+
- "Upgrade to the latest stable actions/checkout release when a new version is available"
|
|
100
|
+
docs:
|
|
101
|
+
- url: "https://github.com/actions/checkout/issues/2299"
|
|
102
|
+
label: "checkout#2299 — Duplicate header: Authorization (Nov 2025, 10 reactions)"
|
|
103
|
+
- url: "https://github.com/actions/checkout/issues/2215"
|
|
104
|
+
label: "checkout#2215 — actions/checkout@v4 fails with Duplicate header: Authorization, 400 (Jul 2025, 8 reactions)"
|
|
105
|
+
- url: "https://docs.github.com/en/actions/security-for-github-actions/security-guides/security-hardening-for-github-actions#using-an-intermediate-environment-variable"
|
|
106
|
+
label: "GitHub Actions security hardening — credential best practices"
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
id: runner-environment-249
|
|
2
|
+
title: '`actions/github-script@v9` breaking changes — `const getOctokit` SyntaxError + `require(''@actions/github'')` ERR_REQUIRE_ESM'
|
|
3
|
+
category: runner-environment
|
|
4
|
+
severity: error
|
|
5
|
+
tags:
|
|
6
|
+
- github-script
|
|
7
|
+
- v9
|
|
8
|
+
- breaking-change
|
|
9
|
+
- getOctokit
|
|
10
|
+
- esm
|
|
11
|
+
- require
|
|
12
|
+
- SyntaxError
|
|
13
|
+
- octokit
|
|
14
|
+
patterns:
|
|
15
|
+
- regex: 'SyntaxError.*Identifier.*getOctokit.*already been declared'
|
|
16
|
+
flags: 'i'
|
|
17
|
+
- regex: "require.*@actions/github.*ERR_REQUIRE_ESM|ERR_REQUIRE_ESM.*@actions/github"
|
|
18
|
+
flags: 'i'
|
|
19
|
+
- regex: 'github-script.*v9.*const getOctokit|const getOctokit.*github-script.*v9'
|
|
20
|
+
flags: 'i'
|
|
21
|
+
- regex: "require.*@actions/github.*ES Module.*not supported"
|
|
22
|
+
flags: 'i'
|
|
23
|
+
error_messages:
|
|
24
|
+
- "SyntaxError: Identifier 'getOctokit' has already been declared"
|
|
25
|
+
- "Error [ERR_REQUIRE_ESM]: require() of ES Module /node_modules/@actions/github/lib/github.js is not supported."
|
|
26
|
+
- "Instead change the require of index.js to a dynamic import() which is available in all CommonJS modules."
|
|
27
|
+
root_cause: |
|
|
28
|
+
`actions/github-script@v9.0.0` (released April 9, 2026) introduced two breaking changes
|
|
29
|
+
compared to v8 and earlier:
|
|
30
|
+
|
|
31
|
+
BREAKING CHANGE 1: `getOctokit` is now an injected function parameter
|
|
32
|
+
In v9, the `getOctokit` factory function is injected directly into the script's
|
|
33
|
+
execution context as a named function parameter (alongside `github`, `context`, `core`,
|
|
34
|
+
etc.). This means `getOctokit` is now a declared parameter name in the script scope.
|
|
35
|
+
|
|
36
|
+
If a script re-declares `getOctokit` using `const` or `let`, JavaScript throws a
|
|
37
|
+
SyntaxError at parse time because re-declaring a `const`/`let` binding that already
|
|
38
|
+
exists in scope is illegal:
|
|
39
|
+
|
|
40
|
+
const getOctokit = require('@octokit/rest').Octokit // ❌ SyntaxError in v9
|
|
41
|
+
let getOctokit = ... // ❌ SyntaxError in v9
|
|
42
|
+
|
|
43
|
+
Using `var` avoids this issue because `var` allows redeclaration in the same scope
|
|
44
|
+
(though the injected value will be shadowed).
|
|
45
|
+
|
|
46
|
+
BREAKING CHANGE 2: `require('@actions/github')` no longer works
|
|
47
|
+
`@actions/github` v9 is an ESM-only package. The `github-script` execution context
|
|
48
|
+
is CommonJS (CJS). Calling `require('@actions/github')` from within a script will
|
|
49
|
+
fail at runtime:
|
|
50
|
+
|
|
51
|
+
const { getOctokit } = require('@actions/github') // ❌ ERR_REQUIRE_ESM in v9
|
|
52
|
+
|
|
53
|
+
This pattern was previously used in v7/v8 scripts to create secondary Octokit
|
|
54
|
+
clients with custom tokens. In v9, this is replaced by the injected `getOctokit`
|
|
55
|
+
function parameter, which eliminates the need to require `@actions/github` at all.
|
|
56
|
+
|
|
57
|
+
Impact: Scripts that used `require('@actions/github')` to create custom clients
|
|
58
|
+
(e.g., for cross-organization access or GitHub App tokens) will fail when the
|
|
59
|
+
action is upgraded or when `@latest` resolves to v9.
|
|
60
|
+
fix: |
|
|
61
|
+
FIX FOR BREAKING CHANGE 1 (SyntaxError: 'getOctokit' already declared):
|
|
62
|
+
Remove or rename the local `getOctokit` variable declaration. The injected
|
|
63
|
+
`getOctokit` is available directly in the script scope without any import.
|
|
64
|
+
If you need to keep the variable name, use `var` instead of `const`/`let` — or
|
|
65
|
+
simply rename the local variable to something else.
|
|
66
|
+
|
|
67
|
+
FIX FOR BREAKING CHANGE 2 (ERR_REQUIRE_ESM from require('@actions/github')):
|
|
68
|
+
Replace the `require('@actions/github')` pattern with the injected `getOctokit`
|
|
69
|
+
function. In v9, `getOctokit(token)` is available directly in the script context
|
|
70
|
+
and accepts a PAT or GitHub App token to create a secondary authenticated client.
|
|
71
|
+
|
|
72
|
+
General recommendation: pin to `actions/github-script@v9` explicitly and
|
|
73
|
+
migrate your scripts using the patterns below.
|
|
74
|
+
fix_code:
|
|
75
|
+
- language: yaml
|
|
76
|
+
label: 'Fix SyntaxError — use injected getOctokit directly, remove const/let redeclaration'
|
|
77
|
+
code: |
|
|
78
|
+
- uses: actions/github-script@v9
|
|
79
|
+
with:
|
|
80
|
+
script: |
|
|
81
|
+
# ❌ v8 and earlier — required declaration to get getOctokit:
|
|
82
|
+
# const { getOctokit } = require('@actions/github')
|
|
83
|
+
# const myOctokit = getOctokit(process.env.MY_TOKEN)
|
|
84
|
+
|
|
85
|
+
# ❌ v9 SyntaxError — can't redeclare the injected getOctokit parameter:
|
|
86
|
+
# const getOctokit = require('@actions/github').getOctokit // SyntaxError!
|
|
87
|
+
|
|
88
|
+
# ✅ v9 — getOctokit is injected directly; use it without any import:
|
|
89
|
+
const myOctokit = getOctokit(process.env.MY_TOKEN)
|
|
90
|
+
const result = await myOctokit.rest.repos.get({
|
|
91
|
+
owner: 'my-org',
|
|
92
|
+
repo: 'my-private-repo',
|
|
93
|
+
})
|
|
94
|
+
core.info(`Repo: ${result.data.full_name}`)
|
|
95
|
+
env:
|
|
96
|
+
MY_TOKEN: ${{ secrets.MY_CROSS_REPO_TOKEN }}
|
|
97
|
+
|
|
98
|
+
- language: yaml
|
|
99
|
+
label: 'Fix ERR_REQUIRE_ESM — replace require(''@actions/github'') with injected getOctokit'
|
|
100
|
+
code: |
|
|
101
|
+
- uses: actions/github-script@v9
|
|
102
|
+
with:
|
|
103
|
+
script: |
|
|
104
|
+
# ❌ v8 pattern — fails with ERR_REQUIRE_ESM in v9:
|
|
105
|
+
# const { getOctokit } = require('@actions/github')
|
|
106
|
+
# const crossOrgClient = getOctokit(process.env.CROSS_ORG_TOKEN)
|
|
107
|
+
|
|
108
|
+
# ✅ v9 pattern — use injected getOctokit directly:
|
|
109
|
+
const crossOrgClient = getOctokit(process.env.CROSS_ORG_TOKEN)
|
|
110
|
+
await crossOrgClient.rest.issues.create({
|
|
111
|
+
owner: 'other-org',
|
|
112
|
+
repo: 'other-repo',
|
|
113
|
+
title: 'Cross-org issue from Actions',
|
|
114
|
+
body: 'Created via github-script v9 getOctokit factory'
|
|
115
|
+
})
|
|
116
|
+
env:
|
|
117
|
+
CROSS_ORG_TOKEN: ${{ secrets.CROSS_ORG_PAT }}
|
|
118
|
+
|
|
119
|
+
- language: yaml
|
|
120
|
+
label: 'Use dynamic import() as alternative for @actions/github internals'
|
|
121
|
+
code: |
|
|
122
|
+
- uses: actions/github-script@v9
|
|
123
|
+
with:
|
|
124
|
+
script: |
|
|
125
|
+
# If you need @actions/github internals beyond getOctokit/github,
|
|
126
|
+
# use dynamic import() — ESM packages can be imported this way in github-script:
|
|
127
|
+
const actionsGithub = await import('@actions/github')
|
|
128
|
+
const customClient = actionsGithub.getOctokit(process.env.MY_TOKEN)
|
|
129
|
+
core.info('Loaded via dynamic import')
|
|
130
|
+
env:
|
|
131
|
+
MY_TOKEN: ${{ secrets.MY_TOKEN }}
|
|
132
|
+
prevention:
|
|
133
|
+
- "Pin `uses: actions/github-script@v9` (not `@latest`) to control when you upgrade and avoid surprise breaking changes"
|
|
134
|
+
- "Remove all `require('@actions/github')` calls from github-script scripts — use the injected `getOctokit` function parameter instead"
|
|
135
|
+
- "Never re-declare `getOctokit`, `github`, `context`, `core`, `exec`, `glob`, `io`, `fetch`, or `require` with `const`/`let` — these are all injected parameters in v9"
|
|
136
|
+
- "When creating secondary Octokit clients, use `getOctokit(token)` directly without any imports — this pattern works in all versions of github-script that inject the factory"
|
|
137
|
+
- "Review the v9.0.0 release notes when upgrading from v8: https://github.com/actions/github-script/releases/tag/v9.0.0"
|
|
138
|
+
docs:
|
|
139
|
+
- url: 'https://github.com/actions/github-script/releases/tag/v9.0.0'
|
|
140
|
+
label: 'actions/github-script v9.0.0 release notes — breaking changes (April 9, 2026)'
|
|
141
|
+
- url: 'https://github.com/actions/github-script#creating-additional-clients-with-getoctokit'
|
|
142
|
+
label: 'actions/github-script README — Creating additional clients with getOctokit (v9 pattern)'
|
|
143
|
+
- url: 'https://github.com/actions/github-script/pull/700'
|
|
144
|
+
label: 'actions/github-script PR#700 — add getOctokit to script context, upgrade @actions/github v9'
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
id: silent-failures-122
|
|
2
|
+
title: '`fetch-tags: false` is silently ignored when `fetch-depth: 0` — all tags are still fetched'
|
|
3
|
+
category: silent-failures
|
|
4
|
+
severity: silent-failure
|
|
5
|
+
tags:
|
|
6
|
+
- checkout
|
|
7
|
+
- fetch-tags
|
|
8
|
+
- fetch-depth
|
|
9
|
+
- git
|
|
10
|
+
- tags
|
|
11
|
+
- shallow-clone
|
|
12
|
+
- option-conflict
|
|
13
|
+
patterns:
|
|
14
|
+
- regex: 'fetch-tags.*false.*fetch-depth.*0|fetch-depth.*0.*fetch-tags.*false'
|
|
15
|
+
flags: 'i'
|
|
16
|
+
- regex: 'tags.*still.*fetched|fetching.*tags.*despite.*false'
|
|
17
|
+
flags: 'i'
|
|
18
|
+
error_messages:
|
|
19
|
+
- "# No error message — tags are silently fetched despite fetch-tags: false"
|
|
20
|
+
root_cause: |
|
|
21
|
+
`actions/checkout` provides two related but conflicting inputs:
|
|
22
|
+
- `fetch-depth: 0` — fetches ALL commits and branches (unshallow clone); this
|
|
23
|
+
implicitly fetches ALL tags as well because full history requires resolving all
|
|
24
|
+
tag references
|
|
25
|
+
- `fetch-tags: false` — instructs the action NOT to fetch tags
|
|
26
|
+
|
|
27
|
+
When BOTH options are used together (`fetch-depth: 0` and `fetch-tags: false`),
|
|
28
|
+
`fetch-tags: false` is silently ignored. The full-history fetch that `fetch-depth: 0`
|
|
29
|
+
triggers uses a git fetch command that includes tag references, and the action does
|
|
30
|
+
not apply a `--no-tags` flag in this code path.
|
|
31
|
+
|
|
32
|
+
As a result, all repository tags end up in the local clone even though the workflow
|
|
33
|
+
explicitly requested `fetch-tags: false`. There is no error, warning, or annotation
|
|
34
|
+
— the tags are simply present.
|
|
35
|
+
|
|
36
|
+
This is a code-path gap in actions/checkout rather than a documented design decision.
|
|
37
|
+
The issue was reported in checkout#2195 (Jun 2025, 10 reactions) and remained open
|
|
38
|
+
as of June 2026.
|
|
39
|
+
|
|
40
|
+
Common situations where this matters:
|
|
41
|
+
- Workflows that use `git describe` and want to avoid picking up pre-release or
|
|
42
|
+
unrelated tags from the full history
|
|
43
|
+
- Versioning scripts that filter by tag presence to determine release status
|
|
44
|
+
- Workflows that check `git tag -l` to decide whether to create a new tag
|
|
45
|
+
fix: |
|
|
46
|
+
Since `fetch-tags: false` is not honoured with `fetch-depth: 0`, the workaround is
|
|
47
|
+
to explicitly delete the fetched tags in a step immediately after checkout:
|
|
48
|
+
|
|
49
|
+
```yaml
|
|
50
|
+
- uses: actions/checkout@v4
|
|
51
|
+
with:
|
|
52
|
+
fetch-depth: 0
|
|
53
|
+
fetch-tags: false # Has no effect — tags are fetched anyway
|
|
54
|
+
|
|
55
|
+
- name: Remove all fetched tags (workaround for fetch-depth:0 + fetch-tags:false bug)
|
|
56
|
+
run: git tag -d $(git tag -l) || true
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Alternatively, if the goal is to avoid tag resolution during git operations, use
|
|
60
|
+
`--no-tags` in subsequent git fetch calls:
|
|
61
|
+
```yaml
|
|
62
|
+
- run: git fetch --no-tags origin
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
If the full commit history is needed but not all tags, also consider filtering
|
|
66
|
+
the specific tags needed using `git fetch origin refs/tags/<specific-tag>:refs/tags/<specific-tag>`
|
|
67
|
+
after deleting the unwanted ones.
|
|
68
|
+
fix_code:
|
|
69
|
+
- language: yaml
|
|
70
|
+
label: "Delete all fetched tags after checkout when fetch-tags: false is needed with full history"
|
|
71
|
+
code: |
|
|
72
|
+
- uses: actions/checkout@v4
|
|
73
|
+
with:
|
|
74
|
+
fetch-depth: 0
|
|
75
|
+
fetch-tags: false # NOTE: currently ignored with fetch-depth: 0
|
|
76
|
+
|
|
77
|
+
- name: Delete all tags (workaround — fetch-tags:false ignored with fetch-depth:0)
|
|
78
|
+
run: |
|
|
79
|
+
TAGS=$(git tag -l)
|
|
80
|
+
if [ -n "$TAGS" ]; then
|
|
81
|
+
git tag -d $TAGS
|
|
82
|
+
fi
|
|
83
|
+
|
|
84
|
+
- language: yaml
|
|
85
|
+
label: "Fetch full history via explicit git command with --no-tags as an alternative"
|
|
86
|
+
code: |
|
|
87
|
+
- uses: actions/checkout@v4
|
|
88
|
+
with:
|
|
89
|
+
fetch-depth: 1 # Shallow initial checkout
|
|
90
|
+
|
|
91
|
+
- name: Fetch full history without tags
|
|
92
|
+
run: git fetch --unshallow --no-tags
|
|
93
|
+
prevention:
|
|
94
|
+
- "Do not rely on fetch-tags: false to suppress tag fetching when fetch-depth: 0 is also set — it has no effect"
|
|
95
|
+
- "If tag presence affects workflow logic, explicitly verify the tag state with git tag -l after checkout"
|
|
96
|
+
- "Track checkout#2195 for a fix in future actions/checkout releases"
|
|
97
|
+
- "As a workaround, delete all tags after checkout using: git tag -d $(git tag -l) || true"
|
|
98
|
+
docs:
|
|
99
|
+
- url: "https://github.com/actions/checkout/issues/2195"
|
|
100
|
+
label: "checkout#2195 — fetch-tags: false still fetches tags if fetch-depth is 0 (Jun 2025, 10 reactions)"
|
|
101
|
+
- url: "https://github.com/actions/checkout#usage"
|
|
102
|
+
label: "actions/checkout Usage — fetch-depth and fetch-tags inputs"
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
id: yaml-syntax-078
|
|
2
|
+
title: '`vars.*` context returns empty string for undefined configuration variables, causing "unexpected value ''" in reusable workflow with: inputs'
|
|
3
|
+
category: yaml-syntax
|
|
4
|
+
severity: error
|
|
5
|
+
tags:
|
|
6
|
+
- vars-context
|
|
7
|
+
- reusable-workflow
|
|
8
|
+
- workflow-call
|
|
9
|
+
- configuration-variables
|
|
10
|
+
- empty-string
|
|
11
|
+
- unexpected-value
|
|
12
|
+
patterns:
|
|
13
|
+
- regex: 'evaluate reusable workflow inputs.*unexpected value'
|
|
14
|
+
flags: 'i'
|
|
15
|
+
- regex: 'vars\.\w+.*unexpected value|unexpected value.*vars\.\w+'
|
|
16
|
+
flags: 'i'
|
|
17
|
+
- regex: 'unexpected value ''''.*reusable.*input|reusable.*input.*unexpected value '''''
|
|
18
|
+
flags: 'i'
|
|
19
|
+
error_messages:
|
|
20
|
+
- "evaluate reusable workflow inputs: key 'my-input': unexpected value ''"
|
|
21
|
+
- "evaluate reusable workflow inputs: unexpected value '' for boolean input"
|
|
22
|
+
- "Error: evaluate reusable workflow inputs: ... unexpected value ''"
|
|
23
|
+
root_cause: |
|
|
24
|
+
When a caller workflow passes a `vars.*` context expression to a reusable workflow's
|
|
25
|
+
`with:` input, and that configuration variable is not defined in the repository or
|
|
26
|
+
organization settings, `${{ vars.SOME_VAR }}` evaluates to an empty string `""`.
|
|
27
|
+
|
|
28
|
+
Reusable workflow inputs that are typed as `boolean` or `number` (or have strict
|
|
29
|
+
validation) reject the empty string `""` with the error:
|
|
30
|
+
evaluate reusable workflow inputs: ... unexpected value ''
|
|
31
|
+
|
|
32
|
+
For `type: boolean` inputs, the only valid values are `"true"` or `"false"`.
|
|
33
|
+
An empty string `""` is not a valid boolean and triggers this error.
|
|
34
|
+
For `type: number` inputs, `""` is not parseable as a number.
|
|
35
|
+
|
|
36
|
+
Even for `type: string` inputs with `required: true`, some versions of the runner
|
|
37
|
+
treat `""` as "not provided" and reject it with this error.
|
|
38
|
+
|
|
39
|
+
Root causes of the empty string:
|
|
40
|
+
1. The developer never created the configuration variable in the repository/organization
|
|
41
|
+
Settings → Variables UI. `vars.*` is the context for configuration variables (set
|
|
42
|
+
in the UI), NOT for environment variables set with `env:` in the workflow YAML.
|
|
43
|
+
2. The variable was created at the wrong scope — e.g., created as an environment-level
|
|
44
|
+
variable but the workflow doesn't reference a matching environment.
|
|
45
|
+
3. The variable name was mistyped — `vars.MY_VAR` but the setting is named `MY_VAr`
|
|
46
|
+
(case-sensitive match is required).
|
|
47
|
+
|
|
48
|
+
This is a common confusion: developers sometimes set `env:` workflow-level variables
|
|
49
|
+
expecting them to be accessible via `vars.*`, but `vars.*` only resolves variables
|
|
50
|
+
set in the GitHub repository/organization/environment Settings UI.
|
|
51
|
+
fix: |
|
|
52
|
+
Option 1 — Create the configuration variable in GitHub Settings:
|
|
53
|
+
Go to your repository (or organization/environment) Settings → Secrets and variables
|
|
54
|
+
→ Actions → Variables tab, and create the variable `SOME_VAR` with the desired value.
|
|
55
|
+
The `vars.SOME_VAR` expression will then resolve correctly.
|
|
56
|
+
|
|
57
|
+
Option 2 — Provide a fallback default using the `||` operator in the caller workflow:
|
|
58
|
+
Pass `${{ vars.SOME_VAR || 'default-value' }}` to avoid passing an empty string when
|
|
59
|
+
the variable is unset. The reusable workflow input then receives `'default-value'`
|
|
60
|
+
instead of `''`.
|
|
61
|
+
|
|
62
|
+
Option 3 — Use the `inputs.` default in the reusable workflow definition:
|
|
63
|
+
In the reusable workflow's `on.workflow_call.inputs`, set a `default:` value so the
|
|
64
|
+
input has a sensible fallback even when the caller passes an empty string.
|
|
65
|
+
|
|
66
|
+
For boolean inputs specifically — always coerce `vars.*` to boolean in the caller:
|
|
67
|
+
Use `${{ vars.ENABLE_FEATURE == 'true' }}` to convert the string variable value to
|
|
68
|
+
a proper boolean rather than passing the raw string.
|
|
69
|
+
fix_code:
|
|
70
|
+
- language: yaml
|
|
71
|
+
label: 'Caller workflow — provide default fallback for undefined vars.*'
|
|
72
|
+
code: |
|
|
73
|
+
jobs:
|
|
74
|
+
call-reusable:
|
|
75
|
+
uses: org/repo/.github/workflows/reusable.yml@main
|
|
76
|
+
with:
|
|
77
|
+
# ❌ Fails with "unexpected value ''" if SOME_ARG_A is not set:
|
|
78
|
+
# some-arg-a: ${{ vars.SOME_ARG_A }}
|
|
79
|
+
|
|
80
|
+
# ✅ Provide a fallback when the variable is unset:
|
|
81
|
+
some-arg-a: ${{ vars.SOME_ARG_A || 'default-value' }}
|
|
82
|
+
|
|
83
|
+
# ✅ For boolean inputs — convert the string to actual boolean:
|
|
84
|
+
# enable-feature: ${{ vars.ENABLE_FEATURE == 'true' }}
|
|
85
|
+
|
|
86
|
+
- language: yaml
|
|
87
|
+
label: 'Reusable workflow — define a default for the input'
|
|
88
|
+
code: |
|
|
89
|
+
# In the reusable workflow definition:
|
|
90
|
+
on:
|
|
91
|
+
workflow_call:
|
|
92
|
+
inputs:
|
|
93
|
+
some-arg-a:
|
|
94
|
+
type: string
|
|
95
|
+
required: false # Make it optional if a default makes sense
|
|
96
|
+
default: 'default-value'
|
|
97
|
+
description: 'Argument A (can be overridden by vars.SOME_ARG_A in caller)'
|
|
98
|
+
|
|
99
|
+
# ✅ Now even if caller passes '' or omits the input, the default is used
|
|
100
|
+
|
|
101
|
+
- language: yaml
|
|
102
|
+
label: 'Caller workflow — coerce vars.* string to boolean for boolean inputs'
|
|
103
|
+
code: |
|
|
104
|
+
jobs:
|
|
105
|
+
call-reusable:
|
|
106
|
+
uses: org/repo/.github/workflows/reusable.yml@main
|
|
107
|
+
with:
|
|
108
|
+
# ❌ Passing vars.ENABLE_FEATURE ('true'/'false' string or '') to bool input:
|
|
109
|
+
# enable-feature: ${{ vars.ENABLE_FEATURE }}
|
|
110
|
+
|
|
111
|
+
# ✅ Coerce the string value to an actual boolean:
|
|
112
|
+
enable-feature: ${{ vars.ENABLE_FEATURE == 'true' }}
|
|
113
|
+
prevention:
|
|
114
|
+
- "Use `vars.*` only for configuration variables set in the GitHub repository/organization/environment Settings UI — not for `env:` YAML workflow variables"
|
|
115
|
+
- "Always provide a `||` fallback when passing `vars.*` to a reusable workflow input: `${{ vars.MY_VAR || 'default' }}`"
|
|
116
|
+
- "For boolean reusable workflow inputs, coerce `vars.*` strings with `${{ vars.FLAG == 'true' }}` instead of passing the raw string"
|
|
117
|
+
- "Verify the variable name and scope in Settings → Secrets and variables → Actions → Variables before using it in a workflow"
|
|
118
|
+
- "Set `required: false` with a `default:` in the reusable workflow definition to make inputs resilient to empty string values"
|
|
119
|
+
docs:
|
|
120
|
+
- url: 'https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/variables#using-the-vars-context-to-access-configuration-variable-values'
|
|
121
|
+
label: 'GitHub Docs — vars context for configuration variables (distinct from env: YAML variables)'
|
|
122
|
+
- url: 'https://docs.github.com/en/actions/sharing-automations/reusing-workflows#using-inputs-and-secrets-in-a-reusable-workflow'
|
|
123
|
+
label: 'GitHub Docs — Using inputs in a reusable workflow (types, required, defaults)'
|
|
124
|
+
- url: 'https://stackoverflow.com/questions/79949037/consumers-callers-vars-value-passed-and-blank-strings-for-reusable-inputs'
|
|
125
|
+
label: "Stack Overflow — Consumer's/caller's vars value passed and blank strings for reusable inputs (May 2026)"
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
id: yaml-syntax-079
|
|
2
|
+
title: 'Invalid (non-IANA) timezone value in on.schedule.cron — actionlint "invalid timezone must be a valid IANA timezone name" + GitHub workflow validation failure'
|
|
3
|
+
category: yaml-syntax
|
|
4
|
+
severity: error
|
|
5
|
+
tags:
|
|
6
|
+
- schedule
|
|
7
|
+
- cron
|
|
8
|
+
- timezone
|
|
9
|
+
- IANA
|
|
10
|
+
- actionlint
|
|
11
|
+
- validation
|
|
12
|
+
- common-mistake
|
|
13
|
+
patterns:
|
|
14
|
+
- regex: 'invalid timezone.*must be a valid IANA timezone name'
|
|
15
|
+
flags: 'i'
|
|
16
|
+
- regex: 'invalid timezone.*schedule event'
|
|
17
|
+
flags: 'i'
|
|
18
|
+
- regex: 'schedule.*timezone.*not.*valid.*IANA|IANA.*timezone.*invalid.*schedule'
|
|
19
|
+
flags: 'i'
|
|
20
|
+
error_messages:
|
|
21
|
+
- 'invalid timezone "PST" in schedule event. it must be a valid IANA timezone name [events]'
|
|
22
|
+
- 'invalid timezone "EST" in schedule event. it must be a valid IANA timezone name [events]'
|
|
23
|
+
- 'invalid timezone "Asia/Somewhere" in schedule event. it must be a valid IANA timezone name [events]'
|
|
24
|
+
- 'invalid timezone "UTC+5" in schedule event. it must be a valid IANA timezone name [events]'
|
|
25
|
+
- 'invalid timezone "India" in schedule event. it must be a valid IANA timezone name [events]'
|
|
26
|
+
root_cause: |
|
|
27
|
+
GitHub Actions added IANA timezone support for scheduled workflows in March 2026. The
|
|
28
|
+
`timezone:` field under `on.schedule` accepts an IANA Time Zone Database name
|
|
29
|
+
(e.g., `America/New_York`, `Europe/London`, `Asia/Tokyo`). GitHub and actionlint both
|
|
30
|
+
validate that the provided string is a recognized IANA timezone name.
|
|
31
|
+
|
|
32
|
+
The most common mistakes are using timezone ABBREVIATIONS or OFFSET STRINGS instead
|
|
33
|
+
of proper IANA names:
|
|
34
|
+
|
|
35
|
+
| Invalid (rejected) | Valid IANA replacement |
|
|
36
|
+
|------------------------|---------------------------------|
|
|
37
|
+
| PST | America/Los_Angeles |
|
|
38
|
+
| EST | America/New_York |
|
|
39
|
+
| CST | America/Chicago |
|
|
40
|
+
| MST | America/Denver |
|
|
41
|
+
| BST | Europe/London |
|
|
42
|
+
| CET / CEST | Europe/Berlin or Europe/Paris |
|
|
43
|
+
| IST | Asia/Kolkata |
|
|
44
|
+
| JST | Asia/Tokyo |
|
|
45
|
+
| AEST | Australia/Sydney |
|
|
46
|
+
| UTC+5 / GMT+5 / +05:30 | Asia/Karachi or Asia/Kolkata |
|
|
47
|
+
| India | Asia/Kolkata |
|
|
48
|
+
|
|
49
|
+
IANA timezone abbreviations (PST, EST, etc.) are NOT part of the IANA Time Zone
|
|
50
|
+
Database specification — they are informal abbreviations used in human communication
|
|
51
|
+
that map ambiguously to multiple official zones. Similarly, UTC offset strings like
|
|
52
|
+
"UTC+5" or "GMT-8" are not valid IANA names.
|
|
53
|
+
|
|
54
|
+
The only valid form is the `Region/City` (or `Region/Sub-Region/City`) format used
|
|
55
|
+
in the IANA TZ database, or the special zones like `UTC`, `Etc/UTC`, `Etc/GMT+N`.
|
|
56
|
+
|
|
57
|
+
Note: actionlint validates IANA timezone strings as of v0.7.4 (March 30, 2026),
|
|
58
|
+
released to support the new `timezone:` field. The check was further fixed in commit
|
|
59
|
+
f48c0a4 to ensure completeness of the timezone validation.
|
|
60
|
+
fix: |
|
|
61
|
+
Replace the timezone abbreviation or offset string with the correct IANA timezone name.
|
|
62
|
+
The IANA Time Zone Database uses `Region/City` format (e.g., `America/New_York`).
|
|
63
|
+
|
|
64
|
+
You can look up your timezone at:
|
|
65
|
+
- https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
|
|
66
|
+
- https://www.iana.org/time-zones
|
|
67
|
+
- https://nodatime.org/TimeZones (interactive timezone selector)
|
|
68
|
+
|
|
69
|
+
Common fixes:
|
|
70
|
+
- `timezone: PST` → `timezone: America/Los_Angeles`
|
|
71
|
+
- `timezone: EST` → `timezone: America/New_York`
|
|
72
|
+
- `timezone: IST` → `timezone: Asia/Kolkata`
|
|
73
|
+
- `timezone: UTC+5:30` → `timezone: Asia/Kolkata`
|
|
74
|
+
fix_code:
|
|
75
|
+
- language: yaml
|
|
76
|
+
label: 'Use IANA timezone names — common US timezone fixes'
|
|
77
|
+
code: |
|
|
78
|
+
on:
|
|
79
|
+
schedule:
|
|
80
|
+
# ❌ PST is NOT a valid IANA name:
|
|
81
|
+
# - cron: '0 9 * * 1-5'
|
|
82
|
+
# timezone: 'PST'
|
|
83
|
+
|
|
84
|
+
# ✅ Use the IANA Region/City format:
|
|
85
|
+
- cron: '0 9 * * 1-5'
|
|
86
|
+
timezone: 'America/Los_Angeles' # Pacific (handles PST/PDT automatically)
|
|
87
|
+
|
|
88
|
+
# Other US regions:
|
|
89
|
+
# timezone: 'America/New_York' # Eastern (EST/EDT)
|
|
90
|
+
# timezone: 'America/Chicago' # Central (CST/CDT)
|
|
91
|
+
# timezone: 'America/Denver' # Mountain (MST/MDT)
|
|
92
|
+
# timezone: 'Pacific/Honolulu' # Hawaii (HST)
|
|
93
|
+
|
|
94
|
+
- language: yaml
|
|
95
|
+
label: 'Use IANA timezone names — India, Europe, Asia fixes'
|
|
96
|
+
code: |
|
|
97
|
+
on:
|
|
98
|
+
schedule:
|
|
99
|
+
# ❌ IST is NOT a valid IANA name:
|
|
100
|
+
# - cron: '30 9 * * *'
|
|
101
|
+
# timezone: 'IST'
|
|
102
|
+
|
|
103
|
+
# ✅ India Standard Time:
|
|
104
|
+
- cron: '30 9 * * *'
|
|
105
|
+
timezone: 'Asia/Kolkata'
|
|
106
|
+
|
|
107
|
+
# Other common IANA names:
|
|
108
|
+
# timezone: 'Europe/London' # UK (BST/GMT)
|
|
109
|
+
# timezone: 'Europe/Berlin' # Germany (CET/CEST)
|
|
110
|
+
# timezone: 'Europe/Paris' # France (CET/CEST)
|
|
111
|
+
# timezone: 'Asia/Tokyo' # Japan (JST)
|
|
112
|
+
# timezone: 'Asia/Shanghai' # China (CST)
|
|
113
|
+
# timezone: 'Australia/Sydney' # Australia Eastern (AEST/AEDT)
|
|
114
|
+
|
|
115
|
+
- language: yaml
|
|
116
|
+
label: 'Fix UTC offset strings — use Etc/GMT or a Region/City name'
|
|
117
|
+
code: |
|
|
118
|
+
on:
|
|
119
|
+
schedule:
|
|
120
|
+
# ❌ UTC offset strings are NOT valid IANA names:
|
|
121
|
+
# - cron: '0 8 * * *'
|
|
122
|
+
# timezone: 'UTC+5:30' # wrong
|
|
123
|
+
# - cron: '0 8 * * *'
|
|
124
|
+
# timezone: 'GMT+5' # wrong
|
|
125
|
+
|
|
126
|
+
# ✅ Use the Region/City form instead:
|
|
127
|
+
- cron: '0 8 * * *'
|
|
128
|
+
timezone: 'Asia/Karachi' # UTC+5 (Pakistan)
|
|
129
|
+
|
|
130
|
+
# Note: Etc/GMT zones use inverted sign convention (POSIX):
|
|
131
|
+
# Etc/GMT-5 is UTC+5 (confusingly inverted) — prefer Region/City names
|
|
132
|
+
prevention:
|
|
133
|
+
- "Always use `Region/City` IANA timezone names (e.g., `America/New_York`) — never abbreviations like PST, EST, IST"
|
|
134
|
+
- "Look up the correct IANA name using the Wikipedia tz database list before using a new timezone"
|
|
135
|
+
- "Run `actionlint` locally (v0.7.4+) before pushing — it validates IANA timezone strings in on.schedule"
|
|
136
|
+
- "Use `UTC` explicitly for UTC schedules — it is a valid IANA name unlike `GMT+0` or `UTC+0`"
|
|
137
|
+
- "Remember that IANA names handle DST automatically (America/New_York switches between EST and EDT); abbreviations like EST are fixed-offset and ambiguous"
|
|
138
|
+
docs:
|
|
139
|
+
- url: 'https://docs.github.com/en/actions/reference/workflows-and-actions/workflow-syntax#onschedule'
|
|
140
|
+
label: 'GitHub Docs — on.schedule syntax including timezone field'
|
|
141
|
+
- url: 'https://en.wikipedia.org/wiki/List_of_tz_database_time_zones'
|
|
142
|
+
label: 'Wikipedia — List of IANA tz database timezone names'
|
|
143
|
+
- url: 'https://github.com/rhysd/actionlint/blob/main/docs/checks.md#cron-syntax-and-iana-timezone-string-at-onschedule'
|
|
144
|
+
label: 'actionlint docs — CRON syntax and IANA timezone string validation at on.schedule'
|
|
145
|
+
- url: 'https://github.com/rhysd/actionlint/issues/638'
|
|
146
|
+
label: 'actionlint #638 — Add support for timezone schedule triggers (fixed in v0.7.4)'
|
|
147
|
+
- url: 'https://github.com/rhysd/actionlint/commit/f48c0a493f9e25e99443136b413cde503258c745'
|
|
148
|
+
label: 'actionlint commit f48c0a4 — fix timezone check is incomplete (March 30, 2026)'
|
package/package.json
CHANGED