Self-hosted GitHub Actions runners encounter permission errors when:
- Docker containerized workflows create files as root
- Git operations fail with "Permission denied" on
.git/FETCH_HEAD,.git/index, etc. - Checkout fails with "Unable to prepare the existing repository"
Already configured with:
- Automated permission fix script
- Scheduled cleanup workflow (every 6 hours)
- Passwordless sudo for workspace ownership fixes
Add the pre-checkout cleanup action as the FIRST step in workflows that run on self-hosted runners.
Copy this directory to your repository:
# From ipfs_accelerate_py to your repo
cp -r .github/actions/pre-checkout-cleanup /path/to/your-repo/.github/actions/In any workflow that uses runs-on: [self-hosted], add this as the first step:
jobs:
your-job:
runs-on: [self-hosted, linux]
steps:
# ⭐ ADD THIS AS FIRST STEP ⭐
- name: Pre-checkout cleanup
uses: ./.github/actions/pre-checkout-cleanup
# Now checkout will work without permission errors
- name: Checkout code
uses: actions/checkout@v4
# ... rest of your workflowname: CI Pipeline
on:
push:
branches: [ main ]
jobs:
test:
runs-on: [self-hosted, linux]
steps:
# IMPORTANT: This must be the first step
- name: Pre-checkout cleanup
uses: ./.github/actions/pre-checkout-cleanup
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Run tests
run: |
python -m pytest tests/- Fixes ownership of root-owned files from previous containerized workflows
- Removes stale git locks (index.lock, *.lock files)
- Configures git safe directory to prevent permission warnings
- Fixes .git permissions if the directory exists
- Uses passwordless sudo (configured via sudoers in ipfs_accelerate_py)
If you can't use the pre-checkout action (workflow uses a different structure), use this pattern:
- name: Manual workspace cleanup
run: |
# Fix ownership of existing workspace
current_user=$(whoami)
if [ -d "${GITHUB_WORKSPACE}" ]; then
sudo -n chown -R "$current_user:$current_user" "${GITHUB_WORKSPACE}" 2>/dev/null || true
find "${GITHUB_WORKSPACE}" -name "*.lock" -delete 2>/dev/null || true
fi
git config --global --add safe.directory "*"
continue-on-error: true
- name: Checkout code
uses: actions/checkout@v4When workflows run Docker containers (especially with volume mounts), files created inside containers are owned by root on the host system. The GitHub Actions runner user (e.g., barberb) cannot delete or modify these files, causing:
Error: EACCES: permission denied, unlink '.git/FETCH_HEAD'
Error: Unable to create '.git/index.lock': Permission denied
The sudoers configuration in ipfs_accelerate_py allows passwordless chown commands for runner workspaces, so the pre-checkout action can fix ownership before actions/checkout runs.
After adding the pre-checkout action, you should see in workflow logs:
✅ Pre-checkout cleanup completed
The checkout action will now run safely
And no more errors like:
- ❌ "EACCES: permission denied, unlink"
- ❌ "Unable to create '.git/index.lock'"
- ❌ "Unable to prepare the existing repository"
-
Check sudoers configuration:
sudo visudo -c ls -la /etc/sudoers.d/runner-fix-permissions
-
Verify passwordless sudo works:
sudo -n chown -R barberb:barberb /home/barberb/actions-runner*/_work/ -
Run manual fix:
bash /home/barberb/ipfs_accelerate_py/.github/scripts/fix_runner_permissions.sh
-
Check runner logs:
ps aux | grep Runner.Listener journalctl -u actions-runner* -f
The ipfs_accelerate_py repository runs automatic cleanup every 6 hours via:
.github/workflows/runner-cleanup.yml.github/scripts/fix_runner_permissions.sh
This ensures all runners stay healthy even if individual workflows forget to use the cleanup action.
Apply this to all repositories using self-hosted runners:
- ✅ ipfs_accelerate_py (already configured)
- ⏳ ipfs_datasets_py (add pre-checkout action)
- ⏳ ipfs_kit_py (add pre-checkout action)
- ⏳ swissknife (add pre-checkout action)
- ⏳ navichat (add pre-checkout action)
Questions? See RUNNER_PERMISSION_FIX_COMPLETE.md for full details.