DevSecOps

GitHub Actions: Common CI/CD Errors and How to Fix Them

DeviDevs Team
6 min read
#github-actions#cicd#troubleshooting#devops#automation

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 ci

Solution 2 - Run as root in container:

jobs:
  build:
    runs-on: ubuntu-latest
    container:
      image: node:20
      options: --user root

Solution 3 - Fix file permissions:

- name: Fix permissions
  run: |
    sudo chown -R $USER:$USER $GITHUB_WORKSPACE
    chmod -R 755 $GITHUB_WORKSPACE

Error: 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 scope

Cause 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-name

Error: 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' label

Cause 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@v4

Error: 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 test

Solution 2 - Cancel redundant workflows:

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

Solution 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 plan

Cause 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 exactly

Cause 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 }}:latest

Error: 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:backend

Error: 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 status

Solution 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 match

Security 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@b4ffde65f46336ab88eb53be808477a3936bae11

Minimal Token Permissions

permissions:
  contents: read  # Only what's needed
 
jobs:
  build:
    permissions:
      packages: write  # Job-level override

Debugging 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: 15

Quick 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

Get CI/CD consulting

Weekly AI Security & Automation Digest

Get the latest on AI Security, workflow automation, secure integrations, and custom platform development delivered weekly.

No spam. Unsubscribe anytime.