GitHub Actions is powerful but can produce confusing errors. This guide covers the most common issues and their solutions.
Error: Permission Denied (EACCES)
Symptom:
Error: EACCES: permission denied, open '/github/workspace/...'
npm ERR! Error: EACCES: permission denied, mkdir '/root/.npm'
Solution 1 - Fix npm permissions:
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install with correct permissions
run: |
npm config set prefix ~/.npm-global
export PATH=~/.npm-global/bin:$PATH
npm ciSolution 2 - Run as root in container:
jobs:
build:
runs-on: ubuntu-latest
container:
image: node:20
options: --user rootSolution 3 - Fix file permissions:
- name: Fix permissions
run: |
sudo chown -R $USER:$USER $GITHUB_WORKSPACE
chmod -R 755 $GITHUB_WORKSPACEError: Checkout Failed - Repository Not Found
Symptom:
Error: fatal: repository 'https://github.com/org/repo/' not found
Error: The process '/usr/bin/git' failed with exit code 128
Cause 1: Private repository without token:
- name: Checkout private repo
uses: actions/checkout@v4
with:
token: ${{ secrets.REPO_ACCESS_TOKEN }} # PAT with repo scopeCause 2: Submodule access:
- name: Checkout with submodules
uses: actions/checkout@v4
with:
submodules: recursive
token: ${{ secrets.PAT_TOKEN }}Cause 3: Wrong repository reference:
# ❌ Wrong - missing owner
uses: actions/checkout@v4
with:
repository: repo-name
# ✅ Correct - full path
uses: actions/checkout@v4
with:
repository: owner/repo-nameError: Secret Not Available
Symptom:
Error: Input required and not supplied: token
Warning: The `set-output` command is deprecated
Cause 1: Fork PR doesn't have access to secrets:
# Secrets are not available in PRs from forks
# Use pull_request_target with caution:
on:
pull_request_target:
types: [labeled]
jobs:
build:
if: contains(github.event.pull_request.labels.*.name, 'safe-to-test')
# Only runs when maintainer adds 'safe-to-test' labelCause 2: Environment secrets not configured:
jobs:
deploy:
runs-on: ubuntu-latest
environment: production # Must exist in repo settings
steps:
- run: echo ${{ secrets.PROD_API_KEY }}Cause 3: GITHUB_TOKEN permissions:
permissions:
contents: read
packages: write
id-token: write # For OIDC
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4Error: Workflow Timeout
Symptom:
Error: The job running on runner GitHub Actions XX has exceeded the maximum execution time of 360 minutes.
Solution 1 - Set explicit timeout:
jobs:
build:
runs-on: ubuntu-latest
timeout-minutes: 30 # Fail fast instead of 6 hours
steps:
- name: Long running step
timeout-minutes: 10
run: npm testSolution 2 - Cancel redundant workflows:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: trueSolution 3 - Optimize with caching:
- name: Cache node modules
uses: actions/cache@v4
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-Error: Artifacts Not Found
Symptom:
Error: Unable to find any artifacts for the associated workflow
Error: Artifact not found for name: build-output
Cause 1: Artifact expired:
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: build-output
path: dist/
retention-days: 30 # Default is 90, max varies by planCause 2: Wrong artifact name in download:
# Job 1: Upload
- uses: actions/upload-artifact@v4
with:
name: my-artifact # Note the exact name
# Job 2: Download
- uses: actions/download-artifact@v4
with:
name: my-artifact # Must match exactlyCause 3: Artifact in different workflow:
# Use workflow_run to access artifacts from another workflow
on:
workflow_run:
workflows: ["Build"]
types:
- completed
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/download-artifact@v4
with:
name: build-output
github-token: ${{ secrets.GITHUB_TOKEN }}
run-id: ${{ github.event.workflow_run.id }}Error: Docker Build/Push Failed
Symptom:
ERROR: denied: requested access to the resource is denied
Error: buildx failed with: ERROR: failed to solve: failed to push
Solution - Proper Docker login:
- name: Login to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: ghcr.io/${{ github.repository }}:latestError: Matrix Strategy Issues
Symptom:
Error: The workflow is not valid. .github/workflows/ci.yml: Unexpected value 'include'
Solution - Correct matrix syntax:
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest]
node: [18, 20]
include:
# Add specific combination
- os: ubuntu-latest
node: 20
experimental: true
exclude:
# Remove specific combination
- os: windows-latest
node: 18
steps:
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node }}Error: Path Filtering Not Working
Symptom:
Workflow runs even when only docs changed.
Solution - Correct paths syntax:
on:
push:
branches: [main]
paths:
- 'src/**'
- 'package.json'
- '!**/*.md' # Ignore markdown files
pull_request:
paths:
- 'src/**'
# For complex filtering, use paths-filter action:
- uses: dorny/paths-filter@v3
id: changes
with:
filters: |
backend:
- 'backend/**'
frontend:
- 'frontend/**'
- if: steps.changes.outputs.backend == 'true'
run: npm run test:backendError: Self-Hosted Runner Issues
Symptom:
Error: The self-hosted runner: runner-name lost communication with the server
Solution 1 - Runner service restart:
# On the runner machine
cd actions-runner
./svc.sh stop
./svc.sh start
./svc.sh statusSolution 2 - Clean runner workspace:
jobs:
build:
runs-on: self-hosted
steps:
- name: Clean workspace
run: |
rm -rf $GITHUB_WORKSPACE/*
rm -rf $GITHUB_WORKSPACE/.[!.]*Solution 3 - Runner labels:
jobs:
build:
runs-on: [self-hosted, linux, x64, gpu] # All labels must matchSecurity Best Practices
Avoid Script Injection
# ❌ Vulnerable to injection
- run: echo "Issue: ${{ github.event.issue.title }}"
# ✅ Safe - use environment variable
- env:
ISSUE_TITLE: ${{ github.event.issue.title }}
run: echo "Issue: $ISSUE_TITLE"Pin Action Versions
# ❌ Risky - could change
uses: actions/checkout@main
# ✅ Better - tag
uses: actions/checkout@v4
# ✅ Best - SHA (immutable)
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11Minimal Token Permissions
permissions:
contents: read # Only what's needed
jobs:
build:
permissions:
packages: write # Job-level overrideDebugging Tips
Enable Debug Logging
# Add to repository secrets:
# ACTIONS_RUNNER_DEBUG = true
# ACTIONS_STEP_DEBUG = true
# Or in workflow:
- name: Debug info
run: |
echo "GitHub Context:"
echo '${{ toJson(github) }}'Tmate Debug Session
- name: Setup tmate session
if: failure()
uses: mxschmitt/action-tmate@v3
timeout-minutes: 15Quick Reference: Common Fixes
| Error | Quick Fix |
|-------|-----------|
| Permission denied | sudo chown -R $USER:$USER . |
| Secret not available | Check environment config |
| Timeout | Add timeout-minutes: 30 |
| Artifact not found | Match names exactly |
| Docker push denied | Add docker/login-action |
| Matrix invalid | Check YAML indentation |
Complex CI/CD Needs?
Building production-grade CI/CD pipelines requires expertise in security, performance, and reliability. Our team specializes in:
- GitHub Actions workflow optimization
- Secure secret management strategies
- Self-hosted runner infrastructure
- Multi-environment deployment pipelines