Comprehensive Guide: GitHub Actions CI/CD for Solana Anchor Projects
A Detailed Report on Common Pitfalls and Their Solutions

1. Introduction to GitHub Actions
What is GitHub Actions?
GitHub Actions is a powerful continuous integration and continuous deployment (CI/CD) platform that automates your software development workflows. It enables you to build, test, and deploy your code directly from your GitHub repository.
Why Use GitHub Actions?
Automation: Automatically run tests on every push or pull request
Consistency: Ensure consistent build environments across all contributors
Early Bug Detection: Catch issues before they reach production
Parallel Execution: Run multiple jobs simultaneously for faster feedback
Reusable Workflows: Share and reuse workflow templates across projects
Cost-Effective: Free for public repositories and includes generous free minutes for private ones
Key Components of GitHub Actions
| Component | Description | Example |
|---|---|---|
| Workflow | An automated procedure defined in YAML | .github/workflows/test.yml |
| Event | What triggers the workflow | push, pull_request, schedule |
| Job | A set of steps executed on the same runner | test, build, deploy |
| Step | Individual tasks within a job | checkout code, install dependencies |
| Action | Reusable units of work | actions/checkout@v4, actions/setup-node@v4 |
| Runner | The virtual machine that executes the job | ubuntu-latest, windows-latest |
Basic Workflow Structure
name: Workflow Name
on:
push:
branches: [main]
pull_request:
branches: [main]
workflow_dispatch: # Manual trigger
jobs:
build-and-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run a command
run: echo "Hello, World!"
2. Common GitHub Actions Errors and Solutions
Category 1: YAML Syntax Errors
Error: Workflow Not Showing in Actions Tab
Symptoms:
Workflow file exists but doesn't appear in the Actions tab
No error messages visible in the interface
Common Causes:
| Error Type | Example | Fix |
|---|---|---|
| Indentation errors | Wrong spacing (tabs vs spaces) | Use 2 spaces, validate with linter |
| Missing keywords | on or jobs omitted |
Include all required sections |
| Invalid structure | Jobs nested incorrectly | Follow the YAML schema |
| Trailing characters | Extra spaces or characters | Remove all trailing spaces |
Example of Invalid YAML:
name: Test
on: [push] # Missing colon after pull_request
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: echo "test" # Wrong indentation
Solution:
name: Test
on:
push:
pull_request: # ✅ Correct structure
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: echo "test"
Prevention:
Use YAML Lint to validate your workflow
Use VS Code with YAML extension for syntax highlighting
Commit and check the Actions tab immediately
Category 2: Path and Directory Issues
Error 1: No Such File or Directory
Symptoms:
Error: An error occurred trying to start process '/usr/bin/bash' with
working directory '/home/runner/work/repo/repo/folder'.
No such file or directory
Common Causes:
| Mistake | Correct | Why |
|---|---|---|
working-directory: hello-world |
working-directory: hello_world |
Folder name mismatch |
paths: "hello-world/**" |
paths: "hello_world/**" |
Inconsistent naming |
working-directory: programs/hello-world |
working-directory: hello_world |
Wrong project structure |
Example of Incorrect Paths:
on:
push:
paths:
- "hello-world/**" # ❌ Wrong folder name
pull_request:
paths:
- "hello_world/**" # ❌ Inconsistent
jobs:
test:
defaults:
run:
working-directory: hello-world # ❌ Folder doesn't exist
Solution:
on:
push:
paths:
- "hello_world/**" # ✅ Consistent with actual folder name
pull_request:
paths:
- "hello_world/**"
jobs:
test:
defaults:
run:
working-directory: hello_world # ✅ Exact folder name
Best Practices for Paths:
Use
ls -lalocally to confirm folder namesBe consistent: use underscore (
_) OR hyphen (-) throughoutUse
**for recursive matching (all subfolders)Test locally with
actto simulate GitHub Actions
Error 2: Trigger Paths Not Matching
Symptoms:
Workflow appears but doesn't run when files change
Push doesn't trigger the expected workflow
Example of Wrong Trigger Configuration:
on:
push:
paths:
- "src/**" # ❌ Folder doesn't exist
Solution:
on:
push:
paths:
- "hello_world/**" # ✅ Correct path
- "README.md" # ✅ Specific file
- "!hello_world/ignore/**" # ✅ Exclude paths
Category 3: Environment and Toolchain Issues
Error: edition2024 Feature Required
Symptoms:
error: failed to parse manifest at `/path/to/cpufeatures-0.3.0/Cargo.toml`
Caused by:
feature `edition2024` is required
The package requires the Cargo feature called `edition2024`,
but that feature is not stabilized in this version of Cargo (1.79.0)
Root Cause:
The
cpufeaturescrate version 0.3.0 uses the experimentaledition2024featureThe GitHub runner's default Rust version (1.79.0) doesn't support it
The
edition2024feature requires Rust 1.85.0 or later
Solutions:
Solution 1: Install Specific Rust Version (Recommended)
steps:
- name: Install Rust
uses: actions-rs/toolchain@v1
with:
toolchain: 1.85.0
override: true
Solution 2: Use Nightly Toolchain
steps:
- name: Install Rust Nightly
uses: actions-rs/toolchain@v1
with:
toolchain: nightly
override: true
Solution 3: Pin Dependency Version
# In Cargo.toml
[patch.crates-io]
cpufeatures = { git = "https://github.com/RustCrypto/utils", rev = "a51fe1b" }
Best Practices:
Always specify a Rust version in CI workflows
Use
actions-rs/toolchainfor reliable version managementTest with multiple Rust versions using matrix builds
Category 4: Git Branch Management
Error: Divergent Branches
Symptoms:
! [rejected] main -> main (fetch first)
error: failed to push some refs
Updates were rejected because the remote contains work that you do not have locally
Visual Explanation:
Local repository (main) Remote repository (origin/main)
───────────────────────── ──────────────────────────────
A - B - C - D - X A - B - C - D - Y
(your commit) (someone else's commit)
- Local is ahead by 1 commit (X)
- Remote is ahead by 1 commit (Y)
- They diverged from common commit D
Solutions:
Solution 1: Rebase (Recommended)
git pull --rebase origin main
Result After Rebase:
A - B - C - D - Y - X' (local main)
^
your commit reapplied on top
Solution 2: Merge
git pull --no-rebase origin main
Result After Merge:
A - B - C - D - X - M
\ /
Y ---
Set Rebase as Default:
git config --global pull.rebase true
Best Practices:
Use
git pull --rebasefor cleaner historyPull before pushing to avoid divergence
Use feature branches for collaborative work
Resolve conflicts locally before pushing
Category 5: Dependency Installation Issues
Error: Node.js or Package Manager Not Found
Symptoms:
Command 'yarn' not found
Command 'npm' not found
Solution:
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'yarn' # Caches dependencies for faster runs
- name: Install dependencies
run: yarn install
Error: Solana CLI Version Issues
Symptoms:
No such file or directory: solana-keygen
anchor: command not found
Solution:
- name: Install Solana CLI
run: |
sh -c "$(curl -sSfL https://release.anza.xyz/v2.1.21/install)"
echo "\(HOME/.local/share/solana/install/active_release/bin" >> \)GITHUB_PATH
- name: Verify Solana Installation
run: solana --version
3. My Complete Journey: From Setup to Success
Project Structure
solana-anchor-smart-contract-examples/
├── .github/
│ └── workflows/
│ └── test-hello-world.yml
├── hello_world/ # Anchor project
│ ├── Anchor.toml
│ ├── Cargo.toml
│ ├── package.json
│ ├── programs/
│ │ └── hello_world/
│ └── tests/
├── README.md
└── .gitignore
Attempt 1: Basic Workflow (Failed)
What I Did Wrong:
Inconsistent path naming (
hello-worldvshello_world)Wrong working directory
No Rust version specification
Result:
Error: No such file or directory
Workflow didn't appear in Actions tab
Attempt 2: Corrected Paths (Partially Worked)
What I Fixed:
Used consistent paths:
hello_world/**Set correct working directory:
hello_worldValidated YAML syntax
Result:
- Workflow appeared but failed with Rust toolchain error
Attempt 3: Full Working Solution
What I Added:
Rust 1.85.0 installation
Proper Solana and Anchor installation
Environment variables for Anchor test
Final Working Workflow:
name: Test Hello World Program
on:
push:
branches: [main]
paths:
- "hello_world/**"
pull_request:
branches: [main]
paths:
- "hello_world/**"
workflow_dispatch:
jobs:
test:
runs-on: ubuntu-24.04
defaults:
run:
working-directory: hello_world
steps:
- uses: actions/checkout@v4
- name: Install Rust
uses: actions-rs/toolchain@v1
with:
toolchain: 1.85.0
override: true
- name: Install Solana CLI
run: |
sh -c "$(curl -sSfL https://release.anza.xyz/v2.1.21/install)"
echo "\(HOME/.local/share/solana/install/active_release/bin" >> \)GITHUB_PATH
- name: Install Anchor
run: cargo install --git https://github.com/coral-xyz/anchor --tag v0.31.1 anchor-cli --locked
- name: Generate keypair
run: solana-keygen new --outfile $HOME/.config/solana/id.json --no-bip39-passphrase --force
- name: Install Node dependencies
run: yarn install
- name: Run Anchor tests
run: anchor test
env:
ANCHOR_PROVIDER_URL: "http://127.0.0.1:8899"
ANCHOR_WALLET: "$HOME/.config/solana/id.json"
4. Best Practices and Recommendations
1. Workflow Organization
# Use descriptive names
name: Test Hello World Program
# Be specific with triggers
on:
push:
branches: [main]
paths:
- "hello_world/**"
workflow_dispatch: # Manual trigger
# Use environment variables for configuration
env:
ANCHOR_VERSION: "0.31.1"
RUST_VERSION: "1.85.0"
2. Caching for Performance
- name: Cache Cargo registry
uses: actions/cache@v3
with:
path: ~/.cargo/registry
key: \({{ runner.os }}-cargo-registry-\){{ hashFiles('**/Cargo.lock') }}
- name: Cache Node modules
uses: actions/cache@v3
with:
path: hello_world/node_modules
key: \({{ runner.os }}-node-modules-\){{ hashFiles('hello_world/yarn.lock') }}
3. Matrix Builds for Multiple Programs
strategy:
matrix:
program: ["hello_world", "counter"]
steps:
- name: Test program
run: |
cd ${{ matrix.program }}
anchor test
4. Error Handling
- name: Run tests
run: anchor test
continue-on-error: false # Fail workflow if tests fail
- name: Upload logs on failure
if: failure()
uses: actions/upload-artifact@v3
with:
name: test-logs
path: |
**/test-ledger/*.log
**/*.txt
5. Troubleshooting Cheat Sheet
| Symptom | Likely Cause | Solution |
|---|---|---|
| Workflow doesn't appear | YAML syntax error | Validate with linter |
| "No such file" error | Wrong path | Check exact folder names |
| Fails during build | Missing toolchain | Add Rust installation step |
| "edition2024" error | Old Rust version | Use Rust 1.85+ |
| Push rejected | Divergent branches | git pull --rebase |
| Cache not working | Wrong cache key | Use hashFiles() |
| Test validator fails | Port conflict | Increase startup_wait |
6. Conclusion
Setting up GitHub Actions for a Solana Anchor project requires attention to detail, especially regarding:
YAML Syntax: Always validate your workflow files
Path Precision: Match exact folder names (underscore vs. hyphen matters!)
Toolchain Version: Specify compatible Rust versions
Git Management: Use rebase to avoid divergent branches
Dependencies: Properly install and cache dependencies
The journey from a failing workflow to a green checkmark is educational and rewarding. Each error teaches you something new about how CI/CD pipelines work and how to debug them effectively.


