CI failures
Status: đ© COMPLETE Last updated: 2026-06-21 Plain-English tagline: âIt works on my machine but the CI is red.â GitHub Actions, Vercel CI, and the cross-platform gotchas that surface only in automated builds.
What this is
A reference for failures in continuous integration â GitHub Actions workflows, Vercelâs build pipeline, and the platform-specific quirks of CI environments. These are subtle because the same code usually runs fine locally.
For build-time failures specifically (which happen in CI too): see Build errors đ©.
âBuilds locally, fails on Vercelâ (recap)
The #1 CI failure pattern. Causes, in order of frequency:
- Case sensitivity â Linux (Vercel) cares; Windows/Mac donât.
- Missing environment variable â not set in Vercel dashboard.
- TypeScript stricter in CI â
tscruns full project check; dev may skip. - DevDependency used in production code â Vercel strips dev deps.
- Node version mismatch â local Node 20, Vercel default may differ.
Reference: Build errors â âBuild succeeded locally but failed on Vercelâ đ©
âGitHub Actions workflow doesnât run on pushâ
What it means: You pushed code with a .github/workflows/x.yml file, but no run shows up in the Actions tab.
Common causes:
- Workflow file has YAML syntax error. GitHub silently skips invalid workflows; check the Actions tab â workflow â there may be a parser warning.
on:trigger doesnât match your push.on: push: branches: [main]wonât run for pushes tofeature/x.- Workflow is in the wrong branch. A workflow only triggers if the workflow file exists in the branch that received the push. New workflows on a feature branch donât trigger until that branch is the one pushed.
- Actions are disabled at the org or repo level.
Fix:
- Validate YAML â paste into yamllint.com or use
actionlint(CLI tool). - Check trigger config â
on: push(no filter) runs on every push. - Enable Actions â repo Settings â Actions â âAllow all actions."
"Workflow runs but fails immediately with no useful logsâ
What it means: The workflow starts but fails before any steps produce meaningful output.
Common causes:
- Bad runner image (
runs-on: ubuntu-latestwas renamed) - Permission error reading secrets
- Concurrency cancellation by a later run
Fix:
- Use stable images:
runs-on: ubuntu-22.04(rather than-latestwhich can shift). - Check the runâs âSet up jobâ log â often the first issue is there.
âSecret access denied / SECRETS object is undefinedâ
What it means: You referenced ${{ secrets.X }} but it came back empty or denied.
Common causes:
- Secret isnât set at the repo / environment level.
- PR from a fork. GitHub blocks secret access for security on forked-PR workflows by default.
- Wrong scope. Repo secrets, environment secrets, organization secrets â they live at different levels.
- Typo in the secret name.
Fix:
- For PRs from forks: use
pull_request_targetevent (with great care â only for trusted operations) orworkflow_dispatch. - Verify scope: Settings â Secrets and variables â Actions â confirm where the secret is defined.
- Print masked status for debugging:
- run: echo "Has secret? ${{ secrets.MY_SECRET != '' }}"
âCache miss every run / builds are slowâ
What it means: Your workflow ostensibly has caching configured but itâs rebuilding from scratch each time.
Common causes:
- Cache key includes a frequently-changing value (date, run ID).
hashFiles()includes files that change every commit.- Cache size exceeds limit (10 GB per repo); old caches are evicted.
- Branch-scoped cache â caches from
mainarenât always available to feature branches.
Fix:
- uses: actions/cache@v4
with:
path: ~/.npm
key: npm-${{ runner.os }}-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
npm-${{ runner.os }}-The restore-keys fallback finds the closest match if exact-key miss.
âMatrix build: one OS fails but the others passâ
What it means: Your strategy.matrix runs on multiple OSes, and one is consistently failing.
Common causes:
- Path separator differences (Windows uses
\, Linux uses/) - Bash-only commands on a Windows runner without
shell: bash - Different available preinstalled tools per OS
Fix:
- Pin shell for cross-platform:
shell: bash(works on all GitHub-hosted runners including Windows via Git Bash). - Use forward slashes in paths â Node handles both.
- Conditional steps for OS-specific logic:
- if: runner.os == 'Windows' run: powershell-specific-command
âfatal: not a git repositoryâ in CIâ
What it means: A step ran before the repo was checked out.
Fix: ensure actions/checkout@v4 is the first step in any job that needs the code:
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
# ... rest of jobâReusable workflow: required input âXâ was not suppliedâ
What it means: A workflow_call workflow expects an input that you didnât provide when calling it.
Fix: match the inputs in the caller workflow:
jobs:
call-deploy:
uses: ./.github/workflows/deploy.yml
with:
environment: production
secrets:
VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }}âBranch protection rule blocks merge despite green checksâ
What it means: Your PR has all checks passing but the merge button is disabled.
Common causes:
- Required reviewers not all approved.
- Required status check name has changed â protection rule still references the old name.
- Branch not up to date with main (if ârequire branches to be up to dateâ is enabled).
- CODEOWNERS requires a specific person who hasnât reviewed.
Fix: check repo Settings â Branches â branch protection rules. Update the required-check name if it has changed.
âWorkflow cancels other runs of itselfâ (or doesnât)
What it means: Multiple runs of the same workflow pile up (or get cancelled aggressively).
Fix: use concurrency:
concurrency:
group: deploy-${{ github.ref }}
cancel-in-progress: true # cancel older runs on the same refThe group key determines what counts as âthe sameâ workflow â by branch, by event, etc.
âactions/checkout: detected token is set but is not the GitHub tokenâ
What it means: You passed a custom token to checkout but its format is wrong.
Fix: for the default GitHub token, omit the token field entirely:
- uses: actions/checkout@v4
# no `with: token: ...` for the default GITHUB_TOKENFor pulling private submodules or using a PAT, supply the right token:
- uses: actions/checkout@v4
with:
token: ${{ secrets.MY_PAT }}
submodules: recursiveâWorkflow runs but produces a âworkflow_runâ event nothing listens forâ
What it means: You set up a workflow with on: workflow_run to chain workflows, and the downstream isnât triggering.
Common causes:
- The trigger event names donât match.
- The downstream workflowâs
on:doesnât includeworkflow_run. - The triggering workflow isnât on
main.
Fix:
# downstream-workflow.yml
on:
workflow_run:
workflows: ["Upstream Workflow Name"] # NAME of workflow, not filename
types: [completed]Workflow names must match exactly.
âOut of minutesâ on GitHub Actions
What it means: Free tier exhausted (2000 minutes/month for private repos on Free tier).
Fix:
- Wait â minutes reset monthly.
- Optimize workflows â cache more, parallelize, run only on relevant paths.
- Self-host runners for high-volume work.
- Upgrade â Pro tier has more minutes.
âVercel preview deploys are failing for one specific branchâ
What it means: Most branches deploy fine but one keeps failing.
Common causes:
- Branch-specific code that depends on a missing env var
- Branch with a renamed file Vercelâs cache hasnât updated
- TypeScript error introduced only on that branch
Fix: look at the Vercel build logs for that specific deploy. The actual error is there. Vercelâs build logs are usually clearer than GitHub Actionsâ default.
See also
- Common errors â index đ©
- Build errors đ©
- Vercel runtime errors đ© đŠ
- Git errors đ©
- CD đ© â the textbook
- GitHub đ© đŠ
- gh CLI cheat sheet đ© đŠ
- Vercel CLI cheat sheet đ© đŠ