@htekdev/actions-debugger 1.0.23 → 1.0.25

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/errors/caching-artifacts/artifact-minimum-retention-one-day.yml +153 -0
  2. package/errors/caching-artifacts/cache-api-propagation-delay-post-save.yml +128 -0
  3. package/errors/caching-artifacts/cache-backend-internal-error-skipped.yml +75 -0
  4. package/errors/caching-artifacts/cache-hit-step-id-case-sensitive-mismatch.yml +95 -0
  5. package/errors/caching-artifacts/cache-save-post-step-skipped-on-failure.yml +114 -0
  6. package/errors/concurrency-timing/deploy-pages-in-progress-deployment-wedged.yml +70 -0
  7. package/errors/concurrency-timing/deployment-review-timeout-expired.yml +88 -0
  8. package/errors/concurrency-timing/job-concurrency-scope-per-run-not-global.yml +81 -0
  9. package/errors/concurrency-timing/merge-queue-concurrency-cancel-blocks-all.yml +86 -0
  10. package/errors/concurrency-timing/reusable-workflow-github-workflow-context-cancel.yml +124 -0
  11. package/errors/concurrency-timing/runner-scale-set-jobs-never-start.yml +123 -0
  12. package/errors/concurrency-timing/runner-temp-dir-race-concurrent-workers.yml +90 -0
  13. package/errors/known-unsolved/artifact-download-url-unauthenticated-404.yml +98 -0
  14. package/errors/known-unsolved/checkout-v6-credentials-docker-run-manual.yml +105 -0
  15. package/errors/known-unsolved/concurrency-groups-repo-scoped-only.yml +138 -0
  16. package/errors/known-unsolved/environment-deployment-false-custom-protection.yml +93 -0
  17. package/errors/known-unsolved/matrix-256-job-limit.yml +142 -0
  18. package/errors/known-unsolved/merge-group-paths-filter-not-supported.yml +137 -0
  19. package/errors/known-unsolved/no-job-allow-failure.yml +73 -0
  20. package/errors/known-unsolved/schedule-cron-hours-long-queue-drift.yml +101 -0
  21. package/errors/permissions-auth/checkout-persist-credentials-token-write.yml +90 -0
  22. package/errors/permissions-auth/checkout-v6-cross-repo-token-override.yml +103 -0
  23. package/errors/permissions-auth/create-github-app-token-cross-job-token-revoked.yml +95 -0
  24. package/errors/permissions-auth/github-token-contents-write-missing-git-push.yml +117 -0
  25. package/errors/permissions-auth/org-actions-policy-blocks-unapproved-action.yml +106 -0
  26. package/errors/runner-environment/codeql-action-v2-deprecated.yml +110 -0
  27. package/errors/runner-environment/macos-26-openssl-3-system-library-breaking.yml +114 -0
  28. package/errors/runner-environment/macos-26-ruby-34-default-upgrade.yml +114 -0
  29. package/errors/runner-environment/macos-26-xcode-default-265-pin-required.yml +99 -0
  30. package/errors/runner-environment/macos-latest-label-switches-to-macos26.yml +127 -0
  31. package/errors/runner-environment/maven-gradle-403-cache-backend-outage.yml +116 -0
  32. package/errors/runner-environment/node20-removed-toolcache-default-node22.yml +104 -0
  33. package/errors/runner-environment/powershell-74-76-threadjob-module-rename.yml +124 -0
  34. package/errors/runner-environment/self-hosted-runner-not-found.yml +134 -0
  35. package/errors/runner-environment/self-hosted-runner-selinux-service-exec-failure.yml +116 -0
  36. package/errors/runner-environment/service-container-no-healthcheck.yml +158 -0
  37. package/errors/runner-environment/setup-node-v5-corepack-pnpm-not-found.yml +101 -0
  38. package/errors/runner-environment/setup-node-yarn-not-installed-self-hosted.yml +76 -0
  39. package/errors/runner-environment/setup-python-externally-managed-env-error.yml +95 -0
  40. package/errors/runner-environment/windows-2019-runner-retired-june2025.yml +118 -0
  41. package/errors/runner-environment/windows-2022-docker-daemon-not-started.yml +108 -0
  42. package/errors/silent-failures/cache-hit-output-string-not-boolean.yml +96 -0
  43. package/errors/silent-failures/checkout-lfs-pointer-not-content.yml +105 -0
  44. package/errors/silent-failures/reusable-workflow-output-skipped-contains-secret.yml +115 -0
  45. package/errors/silent-failures/setup-node-silent-download-exit-zero.yml +105 -0
  46. package/errors/silent-failures/setup-python-truncated-manifest-silent-exit.yml +111 -0
  47. package/errors/silent-failures/undefined-env-expression-empty-string-silent.yml +115 -0
  48. package/errors/silent-failures/windows-powershell-github-output-bash-syntax.yml +118 -0
  49. package/errors/triggers/fork-pr-first-time-contributor-approval-required.yml +142 -0
  50. package/errors/triggers/on-push-branches-glob-star-no-slash-match.yml +78 -0
  51. package/errors/triggers/pull-request-target-env-protection-default-branch-eval.yml +117 -0
  52. package/errors/triggers/required-status-check-renamed-never-passes.yml +87 -0
  53. package/errors/triggers/schedule-cron-self-hosted-runner-not-triggered.yml +107 -0
  54. package/errors/yaml-syntax/case-function-runner-version-too-old.yml +100 -0
  55. package/errors/yaml-syntax/composite-action-run-shell-missing.yml +90 -0
  56. package/errors/yaml-syntax/composite-action-secrets-context-unavailable.yml +99 -0
  57. package/errors/yaml-syntax/github-script-octokit-renamed-to-github.yml +130 -0
  58. package/errors/yaml-syntax/labeler-v5-config-format-breaking.yml +67 -0
  59. package/errors/yaml-syntax/runs-on-expression-array-syntax-error.yml +121 -0
  60. package/errors/yaml-syntax/setup-go-matrix-version-float-coercion.yml +69 -0
  61. package/package.json +1 -1
@@ -0,0 +1,98 @@
1
+ id: known-unsolved-027
2
+ title: "Artifact Download URLs Require GitHub Authentication (404 for Unauthenticated Users)"
3
+ category: known-unsolved
4
+ severity: limitation
5
+ tags:
6
+ - upload-artifact
7
+ - download
8
+ - authentication
9
+ - public-access
10
+ - known-limitation
11
+ patterns:
12
+ - regex: "artifact.*download.*404|artifact.*not found.*auth"
13
+ flags: "i"
14
+ - regex: "artifact.*only.*registered|artifact.*guest.*not found"
15
+ flags: "i"
16
+ error_messages:
17
+ - "404 Not Found when downloading artifact URL without a GitHub session"
18
+ - "Resource not accessible by integration"
19
+ - "Must have push access to repository to list workflow run artifacts"
20
+ root_cause: |
21
+ All GitHub Actions artifact download URLs — both the UI links on the Actions tab and the archive
22
+ URLs returned by the REST API (GET /repos/{owner}/{repo}/actions/artifacts/{artifact_id}/zip)
23
+ — require GitHub authentication. Unauthenticated visitors to public repositories receive a
24
+ 404 Not Found response regardless of the artifact's age or the repository's visibility.
25
+
26
+ This was not always the case. Prior to a GitHub platform change (around late 2020), direct
27
+ artifact archive URLs were publicly accessible without a GitHub account. The change was made
28
+ without a formal deprecation announcement, breaking projects that distributed nightly builds
29
+ or pre-release binaries via artifact URLs linked from documentation or release pages.
30
+
31
+ The REST API endpoint for listing artifacts (GET /repos/{owner}/{repo}/actions/artifacts)
32
+ also requires authentication, preventing anonymous services from discovering or linking
33
+ current artifact URLs.
34
+
35
+ 185 reactions on actions/upload-artifact#51 (open since Feb 2020).
36
+ fix: |
37
+ There is no way to make GitHub Actions artifacts publicly accessible without authentication.
38
+
39
+ Alternatives for distributing build outputs to unauthenticated users:
40
+ 1. GitHub Releases — release assets attached via `softprops/action-gh-release` are publicly
41
+ downloadable without a GitHub account.
42
+ 2. GitHub Pages — deploy build outputs as static files; pages are publicly accessible.
43
+ 3. External storage (S3, GCS, Azure Blob Storage) — upload artifacts to a public bucket
44
+ and provide a stable URL.
45
+ 4. nightly.link proxy — a free service that fetches artifacts via GitHub App auth and
46
+ provides a public redirect URL. URL format:
47
+ https://nightly.link/{owner}/{repo}/workflows/{workflow}/{branch}/{artifact-name}.zip
48
+ fix_code:
49
+ - language: yaml
50
+ label: "Alternative: publish as GitHub Release asset (publicly accessible)"
51
+ code: |
52
+ jobs:
53
+ build-and-release:
54
+ runs-on: ubuntu-latest
55
+ permissions:
56
+ contents: write
57
+ steps:
58
+ - uses: actions/checkout@v4
59
+ - run: ./build.sh -o dist/output.zip
60
+
61
+ # Release assets are publicly downloadable without GitHub login
62
+ - uses: softprops/action-gh-release@v2
63
+ with:
64
+ tag_name: nightly-${{ github.run_number }}
65
+ files: dist/output.zip
66
+ prerelease: true
67
+
68
+ - language: yaml
69
+ label: "Alternative: deploy to GitHub Pages (publicly accessible static files)"
70
+ code: |
71
+ jobs:
72
+ deploy-pages:
73
+ runs-on: ubuntu-latest
74
+ permissions:
75
+ pages: write
76
+ id-token: write
77
+ environment:
78
+ name: github-pages
79
+ steps:
80
+ - uses: actions/checkout@v4
81
+ - run: ./build.sh -o ./public
82
+
83
+ - uses: actions/upload-pages-artifact@v3
84
+ with:
85
+ path: ./public
86
+ - uses: actions/deploy-pages@v4
87
+ prevention:
88
+ - "Never publish artifact download URLs as public links — they are always authentication-gated."
89
+ - "For public distribution of build outputs, use GitHub Releases, GitHub Pages, or an external CDN."
90
+ - "Use nightly.link for zero-config public access to the latest artifact in open-source projects."
91
+ - "Document the authentication requirement in README when directing contributors to artifacts."
92
+ docs:
93
+ - url: "https://github.com/actions/upload-artifact/issues/51"
94
+ label: "actions/upload-artifact #51 — Artifact URLs require GitHub account (185 reactions)"
95
+ - url: "https://nightly.link"
96
+ label: "nightly.link — Public proxy for GitHub Actions artifacts"
97
+ - url: "https://docs.github.com/en/rest/actions/artifacts"
98
+ label: "GitHub REST API — Actions Artifacts (requires auth)"
@@ -0,0 +1,105 @@
1
+ id: known-unsolved-024
2
+ title: "checkout@v6 Git Credentials Inaccessible Inside Manually Invoked Docker Containers"
3
+ category: known-unsolved
4
+ severity: error
5
+ tags:
6
+ - checkout
7
+ - docker
8
+ - credentials
9
+ - git-auth
10
+ - includeif
11
+ - v6
12
+ patterns:
13
+ - regex: "fatal: could not read Username for.*No such device or address"
14
+ flags: "i"
15
+ - regex: "fatal: Authentication failed for.*github\\.com"
16
+ flags: "i"
17
+ - regex: "includeIf\\.gitdir.*git-credentials.*config"
18
+ flags: "i"
19
+ error_messages:
20
+ - "fatal: could not read Username for 'https://github.com': No such device or address"
21
+ - "fatal: Authentication failed for 'https://github.com/org/repo.git'"
22
+ - "remote: Repository not found."
23
+ root_cause: |
24
+ actions/checkout@v6 changed the credential persistence mechanism from HTTP Authorization
25
+ headers written directly into .git/config (the v5 approach) to path-based includeIf.gitdir
26
+ directives that reference a credentials file stored in $RUNNER_TEMP.
27
+
28
+ This mechanism works for GitHub-managed Docker container actions (using: docker), where
29
+ the runner automatically mounts $RUNNER_TEMP into the container as /github/runner_temp
30
+ and configures paths to match. However, it breaks for any workflow step that runs its own
31
+ docker run commands or scripts that spin up Docker containers manually, because:
32
+
33
+ 1. The $RUNNER_TEMP directory is not mounted into the custom container.
34
+ 2. Even if mounted, the includeIf.gitdir path condition requires the workspace to be
35
+ mounted at /github/workspace for the condition to evaluate as true.
36
+ 3. Any docker run at a non-standard path will not satisfy the gitdir condition even if
37
+ the credentials file is accessible.
38
+
39
+ Any workflow step that runs docker run outside of a formal Docker action and then performs
40
+ authenticated repository operations (fetch, clone, publish) inside that container will
41
+ fail to authenticate, even with persist-credentials: true.
42
+
43
+ As of June 2026, a fix is in progress upstream (switching from includeIf.gitdir to
44
+ include.path would eliminate the path-matching requirement) but not yet released.
45
+ No fully clean universal workaround exists.
46
+ Reported in actions/checkout#2359 (12 reactions, open Jan 2026).
47
+ fix: |
48
+ No complete fix available until checkout releases an updated credential mechanism.
49
+
50
+ Option 1 (recommended until fix released): Pin to actions/checkout@v5.
51
+ v5 uses HTTP Authorization headers written directly into .git/config, visible inside any
52
+ Docker container that mounts the workspace. No path-based includeIf is involved.
53
+
54
+ Option 2: Mount RUNNER_TEMP at the expected path inside docker run.
55
+ Add -v "$RUNNER_TEMP:/github/runner_temp" to the docker run command AND mount the
56
+ workspace at /github/workspace. Both mounts are required simultaneously.
57
+
58
+ Option 3: Pass the token explicitly to the container via environment variable.
59
+ Set the GitHub token as an env variable and configure the credential helper inside
60
+ the container entrypoint to use it via the token-embedded remote URL.
61
+ fix_code:
62
+ - language: yaml
63
+ label: "Option 1: Pin to checkout@v5 (recommended until upstream fix)"
64
+ code: |
65
+ - name: Checkout repository
66
+ uses: actions/checkout@v5
67
+ with:
68
+ fetch-depth: 0
69
+ token: ${{ secrets.GITHUB_TOKEN }}
70
+ - language: yaml
71
+ label: "Option 2: Mount RUNNER_TEMP and workspace at expected paths"
72
+ code: |
73
+ - name: Checkout repository
74
+ uses: actions/checkout@v6
75
+ with:
76
+ persist-credentials: true
77
+ - name: Run docker with credentials accessible
78
+ run: |
79
+ docker run \
80
+ -v "$GITHUB_WORKSPACE:/github/workspace" \
81
+ -v "$RUNNER_TEMP:/github/runner_temp" \
82
+ -w /github/workspace \
83
+ my-image:latest ./scripts/build.sh
84
+ - language: yaml
85
+ label: "Option 3: Pass token to container entrypoint"
86
+ code: |
87
+ - name: Run docker with explicit token
88
+ env:
89
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
90
+ run: |
91
+ docker run -e GH_TOKEN="${GH_TOKEN}" my-image:latest ./scripts/release.sh
92
+ prevention:
93
+ - "Do not upgrade to checkout@v6 if your workflow contains manual docker run steps that perform authenticated repository operations inside the container."
94
+ - "Use formal Docker container actions (using: docker in action.yml) instead of manual docker run steps when repository operations inside containers are needed."
95
+ - "Pin checkout to an explicit version and use Dependabot/Renovate to control upgrade timing."
96
+ - "Track actions/checkout#2359 for the upstream fix when released."
97
+ docs:
98
+ - url: "https://github.com/actions/checkout/issues/2359"
99
+ label: "actions/checkout#2359 — checkout@v6 credentials broken with Docker container actions (Jan 2026)"
100
+ - url: "https://github.com/actions/checkout/issues/2386"
101
+ label: "actions/checkout#2386 — related Docker credential issue"
102
+ - url: "https://github.com/actions/checkout/releases/tag/v6.0.0"
103
+ label: "checkout v6.0.0 release notes — credential mechanism change"
104
+ - url: "https://docs.github.com/en/actions/sharing-automations/creating-actions/creating-a-docker-container-action"
105
+ label: "Creating a Docker container action"
@@ -0,0 +1,138 @@
1
+ id: known-unsolved-023
2
+ title: "Concurrency Groups Are Repository-Scoped — Cannot Synchronize Workflows Across Repositories"
3
+ category: known-unsolved
4
+ severity: limitation
5
+ tags:
6
+ - concurrency
7
+ - cross-repository
8
+ - scoping
9
+ - deployment
10
+ - mutex
11
+ - known-limit
12
+ - organization
13
+ patterns:
14
+ - regex: "concurrency.*cross.?repo|cross.?repo.*concurrency"
15
+ flags: "i"
16
+ - regex: "concurrency.*organization|global.*concurrency|multi.?repo.*concurrency"
17
+ flags: "i"
18
+ - regex: "concurrency only works within a single repository"
19
+ flags: "i"
20
+ error_messages:
21
+ - "GitHub Actions concurrency only works within a single repository"
22
+ - "Concurrency groups cannot be shared across repositories — identical group names in different repos run in parallel"
23
+ root_cause: |
24
+ GitHub Actions `concurrency:` groups are evaluated strictly within a single repository.
25
+ Two workflows in different repositories that define identical `concurrency.group` strings
26
+ (e.g., `group: deploy-production`) run in PARALLEL with no coordination — the group
27
+ name has no cross-repository meaning.
28
+
29
+ This is a hard platform-level scope boundary. GitHub's concurrency implementation stores
30
+ group membership state per-repository, so there is no shared namespace between repos.
31
+
32
+ Common scenarios where this surprises teams:
33
+ - Multiple application repos deploying to a shared staging/production environment
34
+ - A monorepo split into microservice repos that must not deploy simultaneously
35
+ - Platform teams providing reusable deploy workflows called from many repos
36
+ - Organizations trying to limit total simultaneous cloud deployments across a fleet
37
+ - Trying to prevent two repos from running the same database migration at once
38
+
39
+ The behavior is counterintuitive because the same concurrency group string CAN
40
+ coordinate same-repo workflows — so teams naturally assume it works cross-repo too.
41
+
42
+ Source: Stack Overflow #79690697 (Make workflow run sequentially for reusable workflow
43
+ — accepted answer explicitly states: "GitHub Actions' concurrency only works within
44
+ a single repository")
45
+ Source: ben-z/gh-action-mutex (community workaround for cross-repo mutex, 500+ stars)
46
+ Source: GitHub Actions docs (concurrency group scope is per-repository)
47
+ fix: |
48
+ There is no native GitHub Actions concurrency primitive that works cross-repository.
49
+ Use one of these architectural workarounds:
50
+
51
+ Workaround 1 — Orchestrator repository with repository_dispatch (recommended):
52
+ Create a central orchestrator repo. Each application repo sends a
53
+ `repository_dispatch` event to the orchestrator. The orchestrator runs the shared
54
+ workflow sequentially using its own concurrency group (single-repo scope is fine
55
+ here because all dispatch events arrive at one repo).
56
+
57
+ Workaround 2 — External mutex via ben-z/gh-action-mutex:
58
+ Uses a dedicated lock repository's branch as a distributed mutex. Works across
59
+ repos because the lock state lives in one shared repository.
60
+
61
+ Workaround 3 — Environment deployment protection with single-slot reviewers:
62
+ A deployment environment with required reviewers can throttle approval-gated
63
+ deployments. Multiple jobs can still enter "waiting" simultaneously, but the
64
+ gate prevents concurrent execution if reviewers approve only one at a time.
65
+
66
+ Workaround 4 — External coordination service (Redis, DynamoDB, Azure Service Bus):
67
+ For production systems at scale, use a lock/queue service all workflows can reach.
68
+ Requires infrastructure management but provides the most reliable behavior.
69
+ fix_code:
70
+ - language: yaml
71
+ label: "Orchestrator pattern: all repos dispatch to a central repo that serializes deploys"
72
+ code: |
73
+ # In each application repo — sends dispatch to orchestrator
74
+ name: Trigger Orchestrated Deploy
75
+ on:
76
+ push:
77
+ branches: [main]
78
+ jobs:
79
+ dispatch:
80
+ runs-on: ubuntu-latest
81
+ steps:
82
+ - name: Dispatch to orchestrator
83
+ run: |
84
+ gh api /repos/myorg/deploy-orchestrator/dispatches \
85
+ --method POST \
86
+ -F event_type=deploy \
87
+ -F client_payload[repo]="${{ github.repository }}" \
88
+ -F client_payload[sha]="${{ github.sha }}"
89
+ env:
90
+ GH_TOKEN: ${{ secrets.ORCHESTRATOR_DISPATCH_PAT }}
91
+
92
+ ---
93
+ # In deploy-orchestrator repo — single-repo concurrency works correctly here
94
+ name: Orchestrated Deploy
95
+ on:
96
+ repository_dispatch:
97
+ types: [deploy]
98
+ concurrency:
99
+ group: deploy-production # Scoped to orchestrator repo — works as intended
100
+ cancel-in-progress: false # Queue all deployments; never skip one
101
+ jobs:
102
+ deploy:
103
+ runs-on: ubuntu-latest
104
+ steps:
105
+ - run: |
106
+ echo "Deploying ${{ github.event.client_payload.repo }} @ ${{ github.event.client_payload.sha }}"
107
+ # ... deploy logic ...
108
+
109
+ - language: yaml
110
+ label: "External mutex using ben-z/gh-action-mutex for cross-repo locking"
111
+ code: |
112
+ jobs:
113
+ deploy:
114
+ runs-on: ubuntu-latest
115
+ steps:
116
+ - name: Acquire cross-repo deployment lock
117
+ uses: ben-z/gh-action-mutex@v1.0-alpha-7
118
+ with:
119
+ branch: mutex-deploy-production # Branch in the shared lock repo
120
+ repo-token: ${{ secrets.MUTEX_REPO_PAT }}
121
+ repository: myorg/locks # Dedicated lock repository
122
+
123
+ - name: Deploy
124
+ run: ./deploy.sh
125
+
126
+ # Lock is automatically released when the job completes (success or failure)
127
+ prevention:
128
+ - "Do not assume identical concurrency group names coordinate across repositories — they have no cross-repo effect."
129
+ - "Design cross-repo deployment sequencing with an explicit architecture before scaling to multiple repos."
130
+ - "Document the serialization mechanism in your runbooks — this is a common architecture surprise for new team members."
131
+ - "Prefer a single orchestrator repo pattern from the start when cross-repo ordering is a requirement."
132
+ docs:
133
+ - url: "https://docs.github.com/en/actions/writing-workflows/choosing-when-your-workflow-runs/using-concurrency"
134
+ label: "GitHub Docs: Using concurrency in GitHub Actions (repo-scoped)"
135
+ - url: "https://stackoverflow.com/questions/79690697/make-workflow-run-sequentially-allowing-one-job-run-at-a-time-for-github-action-reusable-workflow"
136
+ label: "Stack Overflow #79690697: Cross-repo sequential GitHub Actions execution"
137
+ - url: "https://github.com/ben-z/gh-action-mutex"
138
+ label: "ben-z/gh-action-mutex — cross-repo mutex via shared lock repository"
@@ -0,0 +1,93 @@
1
+ id: known-unsolved-029
2
+ title: "deployment:false environment key incompatible with custom deployment protection rules"
3
+ category: known-unsolved
4
+ severity: limitation
5
+ tags:
6
+ - environment
7
+ - deployment
8
+ - protection-rules
9
+ - custom-deployment-protection
10
+ - no-fix
11
+
12
+ patterns:
13
+ - regex: "You cannot (use|disable) deployment.*custom deployment protection"
14
+ flags: "i"
15
+ - regex: "deployment: false.*is not supported.*protection rule"
16
+ flags: "i"
17
+
18
+ error_messages:
19
+ - "You cannot use deployment: false when a custom deployment protection rule is configured for this environment."
20
+ - "Environments with custom deployment protection rules require automatic deployment tracking. Remove deployment: false to proceed."
21
+
22
+ root_cause: |
23
+ GitHub Actions added deployment: false as a new key for environments in March 2026
24
+ (changelog 2026-03-19). This key lets workflows use environment secrets and variables
25
+ without creating a GitHub Deployment record, which was a long-requested feature for
26
+ teams who want secrets management without polluting the Deployments tab.
27
+
28
+ However, the deployment: false key is fundamentally incompatible with custom deployment
29
+ protection rules. Custom deployment protection rules (third-party apps registered via
30
+ the GitHub API to gate deployments) rely on GitHub Deployment events being created —
31
+ the protection rule callback fires when a deployment is created, approves or rejects it,
32
+ and the workflow proceeds based on the response.
33
+
34
+ When deployment: false is set, no Deployment record is created, so there is no event
35
+ to trigger the custom protection rule callback. GitHub therefore blocks the combination
36
+ entirely rather than silently skipping the protection rule check, which could create
37
+ a security bypass.
38
+
39
+ This is a platform-level design constraint with no workaround. Teams that need custom
40
+ deployment protection rules cannot use deployment: false and must keep auto-deployment
41
+ enabled.
42
+
43
+ fix: |
44
+ There is no workaround. If your environment uses a custom deployment protection rule
45
+ (a third-party app that approves or rejects deployments), you cannot use deployment: false.
46
+
47
+ Options:
48
+ 1. Remove the custom deployment protection rule if it is no longer needed, then use
49
+ deployment: false to stop creating Deployment records.
50
+ 2. Keep auto-deployment enabled (omit deployment: false) and accept that deployments
51
+ will appear in the Deployments tab.
52
+ 3. Use a different secrets management strategy (repository secrets, organization secrets,
53
+ or HashiCorp Vault) if you want to avoid environment-scoped secrets entirely.
54
+
55
+ fix_code:
56
+ - language: yaml
57
+ label: "Valid: deployment:false without custom protection rules"
58
+ code: |
59
+ # Works only when the environment has NO custom deployment protection rules
60
+ jobs:
61
+ deploy:
62
+ environment:
63
+ name: staging
64
+ deployment: false # Suppresses Deployment record creation
65
+ runs-on: ubuntu-latest
66
+ steps:
67
+ - run: echo "Using ${{ secrets.STAGING_API_KEY }} without creating a deployment"
68
+
69
+ - language: yaml
70
+ label: "Required: keep deployment enabled when custom protection rules are configured"
71
+ code: |
72
+ # When a custom deployment protection rule (third-party app) is registered
73
+ # on the environment, omit deployment:false entirely
74
+ jobs:
75
+ deploy:
76
+ environment:
77
+ name: production # Has custom protection rule — must create deployment
78
+ runs-on: ubuntu-latest
79
+ steps:
80
+ - run: echo "Deployment record created; custom protection rule fires and must approve"
81
+
82
+ prevention:
83
+ - "Check environment settings in Settings > Environments before adding deployment: false to confirm no custom protection rules are registered."
84
+ - "Document which environments use custom protection rules so team members know deployment: false is unavailable for those environments."
85
+ - "If you need both secrets management and no deployment records, consider migrating secrets to organization-level secrets with repository access restrictions."
86
+
87
+ docs:
88
+ - url: "https://github.blog/changelog/2026-03-19-github-actions-late-march-2026-updates/"
89
+ label: "GitHub Changelog 2026-03-19: Environments without auto-deployment (deployment: false)"
90
+ - url: "https://docs.github.com/en/actions/deployment/targeting-different-environments/using-environments-for-deployment#using-an-environment-without-auto-deployment"
91
+ label: "GitHub Docs: Using an environment without auto-deployment"
92
+ - url: "https://docs.github.com/en/actions/deployment/protecting-deployments/creating-custom-deployment-protection-rules"
93
+ label: "GitHub Docs: Creating custom deployment protection rules"
@@ -0,0 +1,142 @@
1
+ id: known-unsolved-022
2
+ title: "Job Matrix Hard Limit: Maximum 256 Jobs Per Workflow Run"
3
+ category: known-unsolved
4
+ severity: limitation
5
+ tags:
6
+ - matrix
7
+ - strategy
8
+ - job-limit
9
+ - scale
10
+ - known-limit
11
+ - monorepo
12
+ patterns:
13
+ - regex: "256 jobs|matrix.*256|256.*matrix"
14
+ flags: "i"
15
+ - regex: "Job matrix generate.*more than|maximum.*jobs.*workflow.*run"
16
+ flags: "i"
17
+ - regex: "matrix.*maximum.*jobs|generates more than 256"
18
+ flags: "i"
19
+ error_messages:
20
+ - "Job matrix generates more than 256 jobs"
21
+ - "A job matrix can generate a maximum of 256 jobs per workflow run"
22
+ - "The job was not run because it would exceed the maximum number of jobs in a workflow run"
23
+ root_cause: |
24
+ GitHub Actions enforces a hard limit of 256 jobs per workflow run for job matrix strategies.
25
+ This limit applies equally to GitHub-hosted and self-hosted runners and cannot be raised
26
+ via repository or organization settings.
27
+
28
+ The limit is evaluated at workflow run creation time against the total number of matrix
29
+ job combinations. If the computed combination count exceeds 256, the run is blocked.
30
+
31
+ Common matrix combinations that silently approach or exceed the limit:
32
+ - 3 OS × 4 Node.js versions × 22 packages = 264 jobs ❌
33
+ - 4 cloud regions × 4 environments × 17 services = 272 jobs ❌
34
+ - 5 browsers × 4 OS × 13 test shards = 260 jobs ❌
35
+
36
+ This is a long-standing documented constraint. As of the GitHub Actions limits page,
37
+ the 256-job cap has not been increased and no per-organization override is available.
38
+
39
+ Practical impact grows over time: monorepos and test suites that start within the limit
40
+ gradually approach it as services and configuration dimensions are added, with no
41
+ warning until a push suddenly fails workflow creation.
42
+
43
+ Source: GitHub Docs — Usage limits (256 jobs / workflow run)
44
+ Source: cloudposse/github-action-matrix-extended (widely-used community workaround)
45
+ Source: huggingface/transformers PR#28773 (real-world 2-level split at scale)
46
+ fix: |
47
+ There is no way to raise the 256-job limit via settings. Use one of these workarounds:
48
+
49
+ Workaround 1 — Nested matrix via reusable workflows (extends limit to 256² = 65,536):
50
+ Split work into "slices" at the top-level matrix (up to 256 slices), then call a
51
+ reusable workflow that runs its own matrix (up to 256 jobs per slice). Each slice
52
+ × jobs combination stays within the per-run limit.
53
+
54
+ Workaround 2 — `github-action-matrix-extended` by cloudposse:
55
+ Automates the nested slice pattern and supports up to 3 levels (256³ theoretical max).
56
+ Outputs JSON structure consumed by nested matrix strategy calls.
57
+
58
+ Workaround 3 — Path-change filtering via `dorny/paths-filter`:
59
+ Only generate matrix entries for packages/services that changed in the PR. Keeps
60
+ CI fast AND well under the job limit for most runs.
61
+
62
+ Workaround 4 — Reduce matrix dimensions with `include`/`exclude`:
63
+ Test all OS on the latest version; test all versions on one OS. Use `exclude:` to
64
+ prune uncommon OS × version combinations that rarely catch real issues.
65
+ fix_code:
66
+ - language: yaml
67
+ label: "Nested reusable workflow split: top-level generates slices, called workflow runs sub-matrix"
68
+ code: |
69
+ # outer.yml — up to 256 slices × called workflow's matrix (256 each)
70
+ name: Test Suite
71
+ on: [push]
72
+
73
+ jobs:
74
+ generate-slices:
75
+ runs-on: ubuntu-latest
76
+ outputs:
77
+ slices: ${{ steps.gen.outputs.slices }}
78
+ steps:
79
+ - id: gen
80
+ run: |
81
+ # Generate slice IDs from your service list (split into groups)
82
+ python3 -c "
83
+ import json, math
84
+ services = ['svc-' + str(i) for i in range(300)]
85
+ slice_size = 10
86
+ slices = [services[i:i+slice_size] for i in range(0, len(services), slice_size)]
87
+ print('slices=' + json.dumps([json.dumps(s) for s in slices]))
88
+ " >> $GITHUB_OUTPUT
89
+
90
+ run-slice:
91
+ needs: generate-slices
92
+ strategy:
93
+ matrix:
94
+ slice: ${{ fromJSON(needs.generate-slices.outputs.slices) }}
95
+ fail-fast: false
96
+ uses: ./.github/workflows/test-slice.yml
97
+ with:
98
+ services: ${{ matrix.slice }} # JSON string of services for this slice
99
+
100
+ - language: yaml
101
+ label: "Path filtering: only run matrix jobs for changed packages"
102
+ code: |
103
+ jobs:
104
+ detect-changes:
105
+ runs-on: ubuntu-latest
106
+ outputs:
107
+ matrix: ${{ steps.filter.outputs.changes }}
108
+ steps:
109
+ - uses: actions/checkout@v4
110
+ - id: filter
111
+ uses: dorny/paths-filter@v3
112
+ with:
113
+ filters: |
114
+ service-a: ['services/a/**']
115
+ service-b: ['services/b/**']
116
+ service-c: ['services/c/**']
117
+ # ... define one filter per service
118
+
119
+ test:
120
+ needs: detect-changes
121
+ if: needs.detect-changes.outputs.matrix != '[]'
122
+ strategy:
123
+ matrix:
124
+ service: ${{ fromJSON(needs.detect-changes.outputs.matrix) }}
125
+ runs-on: ubuntu-latest
126
+ steps:
127
+ - uses: actions/checkout@v4
128
+ - run: npm test --workspace=services/${{ matrix.service }}
129
+ prevention:
130
+ - "Track total matrix job count — when exceeding 200, plan a nested split before hitting the 256 wall."
131
+ - "Implement path-change filtering early in the project lifecycle to prevent combinatorial explosion."
132
+ - "Prefer `include`/`exclude` pruning over full combinatorial matrices for OS × version coverage."
133
+ - "Design your CI architecture with the 256-job ceiling in mind, especially for monorepos."
134
+ docs:
135
+ - url: "https://docs.github.com/en/actions/administering-github-actions/usage-limits-billing-and-administration#usage-limits"
136
+ label: "GitHub Docs: Usage limits — Job Matrix (256 jobs per workflow run)"
137
+ - url: "https://github.com/cloudposse/github-action-matrix-extended"
138
+ label: "cloudposse/github-action-matrix-extended — nested matrix workaround"
139
+ - url: "https://github.com/dorny/paths-filter"
140
+ label: "dorny/paths-filter — change-based matrix filtering"
141
+ - url: "https://github.com/huggingface/transformers/pull/28773"
142
+ label: "huggingface/transformers PR#28773: Real-world 2-level matrix split"