Error: Resource not accessible by integration
Fix "Resource not accessible by integration": add the missing scope to the permissions block, such as contents: write or pull-requests: write. Covers forks.
RequestError [HttpError]: Resource not accessible by integration
Incident Overview
Fix "Resource not accessible by integration": add the missing scope to the permissions block, such as contents: write or pull-requests: write. Covers forks.
medium fix·6 min read
By Vishvesh Patel·DevOps Engineer·Updated 21 September 2026
RequestError [HttpError]: Resource not accessible by integration
Error: Resource not accessible by integration
at /home/runner/work/_actions/actions/github-script/v7/dist/index.js:8053:21
remote: Permission to acme/myapp.git denied to github-actions[bot].
fatal: unable to access 'https://github.com/acme/myapp/': The requested URL returned error: 403Do this first3 steps
Run these in order. Each one tells you what its output means before you change anything.
• Identify which API call failed
The permission needed follows from the endpoint. Commenting on a PR needs pull-requests write, pushing needs contents write, and publishing a package needs packages write. Grant the specific one rather than guessing.
• Declare the permission on the job
Declaring permissions at job level rather than workflow level keeps the elevated scope on the one job that needs it. Any permission you do not list defaults to none once the block exists.
• Check whether the run came from a fork
No permissions block can grant write to a fork's pull_request run. That is a deliberate security boundary, and the workflow has to be restructured rather than reconfigured.
The GITHUB_TOKEN your workflow is using does not have the permission the API call needs. The message never says which one, so work backwards from the call that failed.
echo "check the step name and the action in the stack trace"
Which permission?
The step name and the failing endpoint tell you:
Note that a PR comment needs pull-requests: write, not issues: write, even though the REST endpoint is under /issues. That one catches people regularly.
Declare it on the job
Once you declare a permissions block, everything you do not list becomes none. That is the opposite of what people expect, and it produces a second failure immediately after fixing the first. Always include contents: read unless the job genuinely needs nothing from the repository.
Job-level is better than workflow-level. A workflow-level block applies the elevated scope to every job in the file, including ones that only run tests.
jobs:
comment:
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write
steps:
- uses: actions/github-script@v7
with:
script: |
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: 'Build passed'
})Why it changed
GitHub moved the default for new repositories to a read-only GITHUB_TOKEN. Older repositories may still default to permissive, which is why a workflow copied from one repository fails in another with no visible difference.
Check: Settings → Actions → General → Workflow permissions.
Leave it on read-only and declare permissions per job. Switching the repository to permissive fixes the error and gives every workflow write access to everything, which is the wrong trade.
Forks: no permissions block will help
A pull_request event from a fork always receives a read-only token, regardless of what the workflow declares, and repository secrets are not available. This is a deliberate boundary: a pull request is untrusted code, and it must not be able to write to your repository or read your secrets.
Three ways to work with it:
Split the workflow. The untrusted part runs on pull_request with no permissions and uploads an artifact. A second workflow on workflow_run has the permissions and reads the artifact:
Use pull_request_target carefully. It runs in the context of the base repository with a writable token and access to secrets. It checks out the base commit by default, which is the point. Explicitly checking out the PR head under pull_request_target runs untrusted code with your secrets available, which is a well-known and serious vulnerability:
Accept it. For a comment on a fork PR, workflow_run is the correct shape and worth the extra file.
remote: Permission to acme/myapp.git denied to github-actions[bot].
Pushing back to the repository
actions/checkout stores the token for you, so no extra credential setup is needed.
One thing to know: a push made with GITHUB_TOKEN does not trigger further workflows. That is deliberate, to prevent infinite loops. If you need the push to trigger a build, use a PAT or a GitHub App token, and think carefully about the loop.
jobs:
release:
permissions:
contents: write
steps:
- uses: actions/checkout@v4
- run: |
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git commit -am "chore: bump version"
git pushProtected branches and rulesets
contents: write is not enough if the branch is protected. github-actions[bot] must also be in the bypass list for the ruleset, or the push is rejected with a 403 that looks identical to a permissions problem.
GitHub Apps and organisation policies
For a GitHub App token, the App's installation permissions cap what any workflow can do. Widening the workflow's permissions cannot exceed them.
Organisation settings can also restrict the default token across every repository, which produces this error in a repository whose own settings look correct.
A checklist
Frequently Asked Questions
Why did my workflow start failing when I copied it to another repository?
Because the default GITHUB_TOKEN permission differs between repositories. GitHub changed the default for newly created repositories to read-only, while older ones may still be set to permissive, so an identical workflow behaves differently. Check Settings → Actions → General → Workflow permissions. The right fix is to leave the repository on read-only and declare an explicit permissions block on the jobs that need more, which also makes the workflow portable rather than dependent on a repository setting.
Why did adding a permissions block break a different step?
Because declaring a permissions block switches every permission you do not list to none, rather than adding to the defaults. So a block containing only pull-requests: write removes the job's ability to read the repository, and actions/checkout then fails. Always include contents: read unless the job genuinely needs nothing from the repository. This catches almost everyone the first time, because the behaviour is the opposite of what an additive block would do.
Can I give a fork's pull request write access?
No, and you should not want to. A pull_request event from a fork always gets a read-only token with no access to secrets, regardless of what the workflow declares, because the pull request contains untrusted code. The supported pattern is to split the work: the untrusted job runs with no permissions and uploads an artifact, and a separate workflow_run workflow with the necessary permissions consumes it. That keeps the privileged half running only code from your own default branch.
Is pull_request_target safe to use?
It is safe when used as designed and dangerous when misused. It runs in the base repository's context with a writable token and access to secrets, and it checks out the base commit rather than the pull request's code, which is precisely what makes it safe. The vulnerability appears when a workflow explicitly checks out github.event.pull_request.head.sha under pull_request_target, because that executes a contributor's code with your secrets in the environment. That pattern has been exploited in the wild and should never be used.
Why does my push succeed but not trigger the next workflow?
Because events created using GITHUB_TOKEN deliberately do not trigger further workflow runs, which prevents a workflow that pushes from triggering itself indefinitely. If you genuinely need the push to start another workflow, authenticate with a personal access token or a GitHub App installation token instead, and think carefully about the loop you are creating. A workflow_run trigger on the current workflow is often a cleaner alternative to chaining through a push.
Reference and practice
Learn the underlying concept
Other CI/CD errors
Free, comprehensive DevOps tutorials and learning roadmaps. Master Docker, Kubernetes, CI/CD, and more.
Get notified about new tutorials and features.
• Roadmaps
• Interview Prep
• Certifications
• Company
© 2026 DevOpsLesson. All rights reserved.
Need to practice this scenario?
Simulate this error condition and practice recovery commands safely in our in-browser terminal.