Fix: Error: Process completed with exit code 1 (GitHub Actions)
The Error
Your GitHub Actions workflow fails and you see:
Error: Process completed with exit code 1Or one of these variations:
Error: Process completed with exit code 2
Error: Process completed with exit code 127
Error: Process completed with exit code 128
##[error]The process '/usr/bin/docker' failed with exit code 1
Error: Action failed with "The template is not valid."The workflow run shows a red X, and the step that failed is collapsed in the logs. You click it, scroll through dozens of lines, and still can’t figure out what went wrong.
Why This Happens
“Process completed with exit code 1” is not the error itself. It’s GitHub Actions telling you that a command in your workflow returned a non-zero exit code. The actual error is somewhere in the log output above that line.
Every step in a GitHub Actions workflow runs a shell command (or a JavaScript/Docker action). When that command exits with code 0, it means success. Any other code means failure:
| Exit Code | Meaning |
|---|---|
| 0 | Success |
| 1 | General error (most common) |
| 2 | Misuse of shell command / invalid arguments |
| 127 | Command not found |
| 128 | Invalid exit argument |
| 137 | Process killed (OOM or timeout — SIGKILL) |
| 139 | Segmentation fault (SIGSEGV) |
The root cause is always in the logs above the exit code message. Here’s how to find it.
Fix 1: Read the Logs Properly
This sounds obvious, but most people don’t read the logs carefully enough. Here’s the efficient way:
- Go to the Actions tab in your repository.
- Click the failed workflow run.
- Click the failed job (the one with the red X).
- Click the failed step to expand it.
- Scroll up from the exit code message. The actual error is above the “Process completed with exit code 1” line, not below it.
Look for lines containing:
error,Error,ERRORfatalFAILEDnot foundpermission deniedNo such file or directory
Pro tip: Click the gear icon at the top of the log viewer and enable Show timestamps. This helps correlate errors with specific commands when a step runs multiple commands.
Pro tip 2: Add set -x at the top of a multi-line run: block to see exactly which command failed:
- run: |
set -x
npm ci
npm run build
npm testThis prints each command before executing it, so you can see which one triggered the failure.
Fix 2: Fix Node.js Step Failures
If your workflow runs npm ci, npm run build, or npm test and fails, the error is almost always in the build or test output, not in GitHub Actions itself.
npm ci fails
npm ERR! code ERESOLVE
npm ERR! ERESOLVE unable to resolve dependency treeYour package-lock.json is out of sync with package.json. Run npm install locally, commit the updated lockfile, and push.
If your project uses a specific Node.js version, make sure the workflow matches:
- uses: actions/setup-node@v4
with:
node-version: '20'A version mismatch between your local machine and CI is one of the most common causes of “works on my machine” failures. If you’re seeing module errors, check Fix: Cannot find module in Node.js.
npm run build fails
The build might succeed locally because of case-insensitive filesystems. macOS and Windows are case-insensitive; Linux (which GitHub Actions runners use) is case-sensitive:
Module not found: Can't resolve './Components/Header'
# The actual file is ./components/Header.tsx (lowercase 'c')Fix the import casing to match the actual filename exactly.
npm test fails
Tests may depend on environment variables, databases, or services that exist locally but not in CI. Check if your tests need a .env file or a running database. See Fix: process.env.VARIABLE_NAME is undefined for environment variable issues.
Fix 3: Fix Python Step Failures
pip install fails
ERROR: Could not find a version that satisfies the requirement somepackage==1.2.3The package version doesn’t exist or was yanked from PyPI. Check requirements.txt for typos or pinned versions that no longer exist.
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- run: pip install -r requirements.txtpytest fails
Same as Node.js tests — look for the actual assertion error or import error in the output. Python tracebacks print the error at the bottom, so scroll to the end of the traceback.
Missing system dependencies
Some Python packages need system libraries to compile:
- run: |
sudo apt-get update
sudo apt-get install -y libpq-dev gcc
pip install -r requirements.txtFix 4: Fix Docker Step Failures
Docker build fails
##[error]The process '/usr/bin/docker' failed with exit code 1Expand the step and look for the actual Docker build error. Common causes:
- COPY failed: file not found. The file path in your Dockerfile doesn’t match the actual file structure. Paths are relative to the build context (usually the repo root).
- RUN command failed. A
RUNcommand in your Dockerfile returned non-zero. Read the output of that specificRUNstep. - Base image not found. The
FROMimage doesn’t exist or requires authentication.
Docker login fails
- uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}Make sure you’re using secrets.GITHUB_TOKEN (not a custom PAT that expired) and that the repository has package write permissions enabled.
Fix 5: Fix Secrets and Environment Variables
Secret is empty or not set
Error: Input required and not supplied: tokenSecrets are not available in:
- Workflows triggered by pull requests from forks. This is a security feature. Forked PRs cannot access your repository secrets.
- Workflows that reference the wrong secret name. Secret names are case-sensitive.
secrets.API_KEYandsecrets.api_keyare different. - Reusable workflows unless you explicitly pass them with the
secretskeyword.
Check your secrets in Settings > Secrets and variables > Actions. Verify the name matches exactly what your workflow references:
env:
API_KEY: ${{ secrets.API_KEY }}Secret expired or was rotated
If a workflow that previously worked suddenly fails, check if the secret (API key, deploy token, SSH key) has expired. Re-create it and update the secret in your repository settings.
Environment variables not available across steps
Each run: step starts a new shell. Variables set in one step are not available in the next:
# WRONG -- $MY_VAR is empty in the second step
- run: export MY_VAR="hello"
- run: echo $MY_VAR
# CORRECT -- use GITHUB_ENV
- run: echo "MY_VAR=hello" >> $GITHUB_ENV
- run: echo $MY_VAR # "hello"For environment variables in general, see Fix: process.env.VARIABLE_NAME is undefined.
Fix 6: Fix GITHUB_TOKEN Permission Errors
Error: Resource not accessible by integration
fatal: could not read Username for 'https://github.com': terminal prompts disabledThe default GITHUB_TOKEN has limited permissions. If your workflow needs to push commits, create releases, or write to packages, you need to explicitly grant permissions:
permissions:
contents: write
packages: write
pull-requests: writeAdd this at the job level or workflow level:
jobs:
deploy:
runs-on: ubuntu-latest
permissions:
contents: write
packages: write
steps:
- uses: actions/checkout@v4
# ...Important: When you set permissions explicitly, you only get the permissions you list. All others default to none. If you only set contents: write, you lose the default read access to other scopes.
Common permission requirements:
| Action | Required Permission |
|---|---|
| Push commits | contents: write |
| Create/update PRs | pull-requests: write |
| Push Docker images to GHCR | packages: write |
| Deploy to GitHub Pages | pages: write, id-token: write |
| Comment on issues | issues: write |
| Read private repos (submodules) | contents: read on the target repo |
Fix 7: Fix Checkout Issues
Shallow clone missing commits
fatal: couldn't find remote refBy default, actions/checkout does a shallow clone (depth 1). If your build needs the full Git history (for changelogs, version calculation, or git diff):
- uses: actions/checkout@v4
with:
fetch-depth: 0 # full historySubmodules not checked out
fatal: No url found for submodule path 'some/submodule'- uses: actions/checkout@v4
with:
submodules: recursive
token: ${{ secrets.PAT_TOKEN }} # if submodules are private reposThe default GITHUB_TOKEN only has access to the repository the workflow runs in. For private submodules, you need a Personal Access Token (PAT) with access to those repositories.
Wrong branch checked out
In pull request workflows, actions/checkout checks out the merge commit by default. If you need the PR head branch:
- uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha }}Fix 8: Fix Caching Failures
Cache miss every time
Cache not found for input keys: ...The cache key doesn’t match any existing cache. Common mistakes:
- Using a key that changes every run (like a timestamp or commit SHA). Use a key based on your lockfile hash:
- uses: actions/cache@v4
with:
path: ~/.npm
key: npm-${{ runner.os }}-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
npm-${{ runner.os }}-- Caching the wrong path.
node_modulesis not a good cache target (it’s platform-dependent). Cache the npm/yarn/pnpm cache directory instead. - Cache eviction. GitHub evicts caches not accessed in 7 days or when the 10 GB limit per repo is hit. Old caches from stale branches fill up the limit.
Cache restore succeeds but build still fails
The cache might be corrupted or stale. Clear it:
gh cache delete --allOr change the cache key to force a fresh cache.
Fix 9: Fix Timeout Failures
Error: The operation was canceled.
##[error]The runner has received a shutdown signal.Job timeout
The default timeout for a job is 360 minutes (6 hours). If your job takes too long, set a shorter timeout so you get faster feedback:
jobs:
build:
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
# ...Step timeout
Individual steps can also hang. Set a per-step timeout:
- run: npm test
timeout-minutes: 10Hung processes
If a step hangs (waiting for user input, a server that never responds, an infinite loop), the job will run until the timeout. Common culprits:
- Interactive prompts. A CLI tool asks for confirmation. Add
-yor--yesflags, or setCI=truein the environment. - A server started without backgrounding.
npm startin a workflow step will block forever. Background it or use a tool designed for CI. - Tests waiting for a database connection. The database service isn’t ready yet. Add a health check wait loop.
Fix 10: Fix Self-Hosted Runner Issues
Runner is offline
Error: The self-hosted runner: [name] is offline.The runner service isn’t running, or it lost network connectivity. SSH into the runner machine and check:
cd /path/to/actions-runner
./svc.sh status
./svc.sh startMissing tools on self-hosted runners
Unlike GitHub-hosted runners, self-hosted runners don’t come with pre-installed tools. If your workflow uses actions/setup-node or actions/setup-python, these actions install the tools, but direct commands like node, docker, or python must already be on the PATH.
Install missing tools on the runner or add setup steps to your workflow.
Working directory not clean
Self-hosted runners persist the working directory between runs. Stale files from a previous run can cause failures:
- uses: actions/checkout@v4
with:
clean: true # default is true, but verifyOr add a cleanup step:
- run: git clean -ffdxFix 11: Fix Matrix Strategy Failures
Error: Process completed with exit code 1With a matrix strategy, one failing combination kills the entire matrix by default. To let other combinations continue:
strategy:
fail-fast: false
matrix:
node-version: [18, 20, 22]
os: [ubuntu-latest, windows-latest]If only one matrix combination fails, the issue is likely platform-specific or version-specific. Check the logs for that specific combination.
Common matrix pitfalls
- Path separators. Windows uses
\, Linux uses/. Usepath.join()orpath.resolve()in Node.js instead of hardcoded paths. - Shell differences. Windows runners use PowerShell by default, not bash. Force bash if your commands need it:
- run: echo "hello"
shell: bash- Case sensitivity. File imports that work on Windows/macOS fail on Linux because Linux filesystems are case-sensitive.
Fix 12: Fix Artifact Upload/Download Failures
Upload fails
Error: Artifact upload failed. Please try again.
Warning: No files were found with the provided pathThe path you specified doesn’t match any files. Paths are relative to the workspace root ($GITHUB_WORKSPACE):
- uses: actions/upload-artifact@v4
with:
name: build-output
path: dist/ # relative to repo root
if-no-files-found: error # fail explicitly if no files foundIf the build step creates output in a different directory, verify the path:
- run: ls -la dist/ # debug: check if files exist before upload
- uses: actions/upload-artifact@v4
with:
name: build-output
path: dist/Download fails in a different workflow
Artifacts are scoped to a workflow run. You cannot download artifacts from a different workflow run using actions/download-artifact directly. Use the GitHub API or gh run download instead.
Artifact size too large
GitHub limits artifact storage. Compress before uploading:
- run: tar -czf build.tar.gz dist/
- uses: actions/upload-artifact@v4
with:
name: build-output
path: build.tar.gz
retention-days: 5Fix 13: Use Conditional Steps to Debug
When a step fails, subsequent steps are skipped by default. Use if: always() to run cleanup or debug steps regardless:
- run: npm test
continue-on-error: true
- run: cat test-results.xml
if: always()
- uses: actions/upload-artifact@v4
if: always()
with:
name: test-results
path: test-results.xmlOther useful conditionals:
# Run only on failure
- run: docker logs my-container
if: failure()
# Run only on success
- run: echo "All tests passed"
if: success()
# Run only on the main branch
- run: npm run deploy
if: github.ref == 'refs/heads/main'Fix 14: Fix YAML Syntax Errors
Error: Invalid workflow file: .github/workflows/ci.yml
The workflow is not valid. .github/workflows/ci.yml (Line X, Col Y): ...Your workflow YAML has a syntax error. Common mistakes:
- Incorrect indentation. YAML uses spaces, not tabs. Every level is 2 spaces:
# WRONG
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
# CORRECT
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4- Missing quotes around expressions. Strings containing
{or special characters need quoting:
# WRONG -- YAML parser breaks on the colon
run: echo Status: ${{ job.status }}
# CORRECT
run: echo "Status: ${{ job.status }}"- Multiline strings done wrong:
# Use | for literal multiline
run: |
echo "line 1"
echo "line 2"For more YAML errors, see Fix: YAML mapping values are not allowed here.
Still Not Working?
The set -e behavior in shell steps
GitHub Actions runs each run: step with set -e by default (for bash). This means the step fails on the first command that returns non-zero, even if subsequent commands would have fixed the state. This catches you when you write:
- run: |
grep "pattern" file.txt # exit code 1 if no match -- kills the step
echo "continuing..." # never runsFix it by handling expected non-zero exits:
- run: |
grep "pattern" file.txt || true
echo "continuing..."Or for a command where you want to check the exit code:
- run: |
if grep -q "pattern" file.txt; then
echo "Found"
else
echo "Not found"
fiWorkflow runs on the wrong trigger
Your workflow might be triggering on pushes to all branches when you only want main, or not triggering on PRs at all:
on:
push:
branches: [main]
pull_request:
branches: [main]Check the on: section carefully. A missing branches filter means the workflow runs on every push to every branch.
Actions version pinning issues
If you use @v4 or @main, the action’s code can change under you. Pin to a specific commit SHA for stability:
# Instead of:
- uses: actions/checkout@v4
# Pin to a specific SHA:
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1This also protects against supply chain attacks on third-party actions.
Rate limiting and API failures
GitHub API calls in your workflow may hit rate limits, especially in workflows that run frequently:
Error: API rate limit exceeded for installationReduce API calls, add retries with backoff, or use a GitHub App token with higher rate limits instead of the default GITHUB_TOKEN.
Runner disk space full
GitHub-hosted runners have limited disk space (~14 GB free). Large builds, Docker images, or cached dependencies can fill it:
- run: df -h # check disk space
# Free up space if needed
- run: |
sudo rm -rf /usr/share/dotnet
sudo rm -rf /opt/ghc
sudo rm -rf /usr/local/share/boost
df -hServices container not ready
If your workflow uses service containers (like PostgreSQL or Redis), they may not be ready when your tests start:
services:
postgres:
image: postgres:16
env:
POSTGRES_PASSWORD: postgres
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
- 5432:5432The --health-cmd option tells GitHub Actions to wait until the service is healthy before starting your steps. Without it, your tests may fail with connection errors.
Concurrency conflicts
Multiple workflow runs on the same branch can interfere with deployments. Use concurrency groups to cancel or queue runs:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: trueThis cancels the previous run when a new push arrives, saving runner minutes and avoiding conflicting deployments.
Enable debug logging
If you still can’t figure out the error, enable debug logging by adding this secret to your repository:
- Name:
ACTIONS_RUNNER_DEBUG - Value:
true
And for step-level debug logs:
- Name:
ACTIONS_STEP_DEBUG - Value:
true
This produces verbose output on the next workflow run. Remove these secrets when you’re done debugging — they generate a lot of noise.
Related: Fix: YAML mapping values are not allowed here | Fix: process.env.VARIABLE_NAME is undefined | Fix: bash permission denied | Fix: Docker Permission Denied While Trying to Connect to the Docker Daemon Socket | Fix: Cannot find module in Node.js | Fix: npm ERR! Missing script: “start”
Related Articles
Fix: SSL certificate problem: unable to get local issuer certificate
How to fix 'SSL certificate problem: unable to get local issuer certificate', 'CERT_HAS_EXPIRED', 'ERR_CERT_AUTHORITY_INVALID', and 'self signed certificate in certificate chain' errors in Git, curl, Node.js, Python, Docker, and more. Covers CA certificates, corporate proxies, Let's Encrypt, certificate chains, and self-signed certs.
Fix: YAML 'mapping values are not allowed here' and Other YAML Syntax Errors
How to fix 'mapping values are not allowed here', 'could not find expected :', 'did not find expected key', and other YAML indentation and syntax errors in Docker Compose, Kubernetes manifests, GitHub Actions, and config files.
Fix: Docker Volume Permission Denied – Cannot Write to Mounted Volume
How to fix Docker permission denied errors on mounted volumes caused by UID/GID mismatch, read-only mounts, or SELinux labels.
Fix: Docker Pull Error – Image Not Found or Manifest Unknown
How to fix Docker errors like 'manifest for image not found', 'repository does not exist', or 'pull access denied' when pulling or running images.