Diagnosing 'Permission Denied' Errors in GitHub Actions Checkout Steps
Learn how to diagnose and fix 'Permission denied' errors in GitHub Actions checkout steps by verifying PAT scopes and token configurations.
22 Dec 2025, 21:39 UTC

The Problem: Checkout Failures Due to Insufficient Token Scopes
When a GitHub Actions workflow fails during the actions/checkout step with a "Permission denied" or "Repository access denied" error, it usually indicates that the authentication token provided to the runner lacks the necessary scopes to access the repository's contents. This is common when workflows transition from simple triggers (like push) to complex triggers (like repository_dispatch or schedule) that may require a Personal Access Token (PAT) instead of the default GITHUB_TOKEN.
Diagnostic Matrix: Identifying the Root Cause
| Error Symptom | Likely Cause | Required Scope/Permission |
|---|---|---|
Permission denied (publickey) |
Token lacks access to private repository | repo (Full control of private repositories) |
403 Forbidden during workflow update |
Token cannot modify workflow files | workflow (Update GitHub Action workflows) |
| Intermittent failures after several months | Token has expired | N/A (Token renewal required) |
404 Not Found for private repo |
Token is invalid or lacks any repo access | repo |
Step-by-Step Verification Process
Follow these checks in order to isolate whether the failure is due to the token's configuration or the runner's environment.
1. Inspect the Workflow Log
Navigate to the failed workflow run and expand the actions/checkout step. Look for the specific HTTP response code. A 403 confirms the token is recognized but lacks permission; a 401 suggests the token is invalid or expired.
2. Validate Token Scopes via CLI
If you have access to the token locally or via a secure debug step, use the GitHub CLI (gh) to verify the current scopes. Run this command from a terminal where the token is configured:
gh auth status
Expected Result: The output should explicitly list repo and workflow if the action involves private code or workflow modifications.
3. Test with a Minimal Permissions Workflow
To rule out complex logic errors, create a temporary test workflow file (e.g., .github/workflows/test-token.yml) to verify the secret's reach:
name: Token Scope Test
on: workflow_dispatch
jobs:
check-access:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
token: <your_secret_name
Risk: Never echo the actual token to the logs. GitHub masks secrets, but avoid printing them to avoid accidental exposure in third-party logs.
Fixing the Permission Gap
Scenario A: The Token Lacks Scopes
If the diagnostic shows missing scopes, you must update the PAT:
- Navigate to Settings > Developer settings > Personal access tokens.
- Select the token used by the workflow.
- Check the
repobox (for private repository access) and theworkflowbox (if the action modifies YAML files in.github/workflows/). - Save the changes. No need to update the repository secret if the token string itself hasn't changed.
Scenario B: Transitioning from GITHUB_TOKEN to PAT
The default GITHUB_TOKEN is limited to the current repository. If your workflow needs to check out a different private repository, you must use a PAT stored as a secret.
Configuration Example:
- uses: actions/checkout@v4
with:
repository: organization/other-private-repo
token: <secrets.MY_CUSTOM_PAT
Limitations and Compliance
- Least Privilege: Avoid using "Classic" PATs with full
repoaccess if Fine-grained PATs are available. Fine-grained tokens allow you to restrict access to specific repositories rather than all repositories the user can see. - Enterprise Policies: Some GitHub Enterprise Server (GHES) environments disable PATs in favor of GitHub Apps. If PATs are disabled, you must configure an App Installation Token.
- Self-Hosted Runners: If using a self-hosted runner, ensure the runner's OS user has write permissions to the
_workdirectory, as "Permission denied" can occasionally refer to local filesystem errors rather than API errors.
Rollback Procedure
If updating the token scopes causes unexpected behavior in other workflows sharing that token:
- Return to Developer settings.
- Uncheck the newly added scopes.
- Save the token.
- Re-run the failed workflow to confirm it returns to the original "Permission denied" state.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.