{"schemaVersion":"1.0","canonicalUrl":"https://automationtester.in/failures/github-actions-resource-not-accessible-by-integration","slug":"github-actions-resource-not-accessible-by-integration","title":"GitHub Actions: Resource not accessible by integration","searchTitle":"Resource not accessible by integration","signature":"Resource not accessible by integration","description":"Resource not accessible by integration: a 403 from the GitHub API because GITHUB_TOKEN or the App token lacks the permission. Find which one, and why.","frameworks":["GitHub Actions","CI"],"classification":"dependency","summary":"A GitHub API call made with the workflow's GITHUB_TOKEN, or with a GitHub App token, returned 403 because that token does not hold the permission the endpoint needs. Posting PR comments, adding labels and creating releases are the usual places it appears.","repro":{"versions":["actions/github-script@v9","GitHub Actions runner 2.338.1"],"files":[{"path":".github/workflows/comment.yml","language":"yaml","code":"on: pull_request\npermissions:\n  contents: read\njobs:\n  comment:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/github-script@v9\n        with:\n          script: |\n            await github.rest.issues.createComment({\n              ...context.repo,\n              issue_number: context.issue.number,\n              body: \"Report attached\",\n            })"}],"command":"Open a pull request against the repository.","output":"GITHUB_TOKEN Permissions\n  Contents: read\n  Metadata: read\nRun actions/github-script@v9\nError: Unhandled error: HttpError: Resource not accessible by integration - https://docs.github.com/rest/issues/comments#create-an-issue-comment\nRequestError [HttpError]: Resource not accessible by integration - https://docs.github.com/rest/issues/comments#create-an-issue-comment\n  status: 403,\n  response: {\n    headers: {\n      'x-accepted-github-permissions': 'issues=write; pull_requests=write',\n\n# The stack trace and the other response headers are trimmed.","ran":"locally","ranOn":"2026-10-23"},"causes":[{"title":"A permissions block left the needed scope out","explanation":"Once a workflow or job sets permissions, every permission it does not list is set to none. The repro asks only for contents: read, so the comment call has neither issues nor pull-requests write. GitHub's REST reference lists Issues (write) or Pull requests (write) for Create an issue comment.","diagnostic":"Look up the endpoint in the REST reference, or read the X-Accepted-GitHub-Permissions response header, which names the permissions it accepts. Then compare with the job's permissions block.","fix":"Add the narrowest permission the endpoint lists (here `pull-requests: write`) at job level, not write-all at workflow level."},{"title":"The run came from a fork or from Dependabot","explanation":"For pull request events other than pull_request_target from a fork, GitHub turns every write permission into read unless an admin enabled Send write tokens to workflows from pull requests. Dependabot runs are treated the same way. The permissions key cannot grant write here.","diagnostic":"Check whether the failing run's head repository differs from the base, or whether the actor is dependabot[bot]. The same workflow passing on a branch in the base repository confirms it.","fix":"Split the work: the pull_request workflow computes the result and uploads it as an artifact; a workflow_run workflow in the base repository posts it, treating the artifact as untrusted data. Do not move it to pull_request_target casually: GitHub's default policy starts blocking that event in public repositories on November 2, 2026."},{"title":"The repository or organization default is restricted","explanation":"The token starts from the enterprise, organization or repository default. If that default is the restricted one, a workflow without a permissions block gets read-only contents and packages, and anything that writes fails.","diagnostic":"Check Settings, Actions, General, Workflow permissions for the repository and its organization.","fix":"Leave the restricted default in place and grant the one write permission in the job that needs it."},{"title":"GITHUB_TOKEN cannot do this at all","explanation":"GITHUB_TOKEN is scoped to the repository running the workflow. Writing to another repository, or to organization-level resources, needs a GitHub App installation token or another credential with that access.","diagnostic":"If the call targets a different owner or repository than github.repository, this is the cause.","fix":"Use a GitHub App installation token scoped to the target repository, created in the job that needs it."}],"verifiedFix":{"summary":"Grant the single permission the endpoint names, in the job that calls it.","files":[{"path":".github/workflows/comment.yml (job)","language":"yaml","code":"jobs:\n  comment:\n    runs-on: ubuntu-latest\n    permissions:\n      contents: read\n      pull-requests: write"}],"evidence":"Run on 2026-10-23 as two jobs in one workflow, on a pull request from a branch in the same repository: the job with only contents: read failed with the 403 above, and the response's x-accepted-github-permissions header named issues=write; pull_requests=write. A second job with pull-requests: write added, and nothing else changed, logged PullRequests: write under GITHUB_TOKEN Permissions and posted its comment as github-actions[bot]. The fork case was not run; it follows GitHub's GITHUB_TOKEN reference."},"notTheCause":[{"title":"A wrong or expired token","explanation":"Invalid credentials get 401 with Bad credentials, not 403. We checked: a request to api.github.com/user with a made-up bearer token returned {\"message\": \"Bad credentials\", \"status\": \"401\"}."},{"title":"write-all fixes fork runs","explanation":"It does not. For fork pull requests the write permissions are downgraded after the workflow's own settings are applied, whatever the workflow asks for."},{"title":"The personal access token variant","explanation":"Resource not accessible by personal access token is the same check for a fine-grained PAT. The fix is on the token's settings page, not in the workflow's permissions block."}],"prevention":["Set permissions per job and start from contents: read.","Design anything that writes back to a PR to work from forks: pull_request plus workflow_run.","Review permission changes in workflow files like code."],"related":["dns-resolution-failed-in-ci","docker-cannot-connect-to-daemon"],"references":[{"label":"GitHub Docs: GITHUB_TOKEN permissions reference","url":"https://docs.github.com/en/actions/reference/github_token-reference"},{"label":"GitHub Docs: REST API troubleshooting, Resource not accessible","url":"https://docs.github.com/en/rest/using-the-rest-api/troubleshooting-the-rest-api"},{"label":"GitHub Docs: REST issue comments, required permissions","url":"https://docs.github.com/en/rest/issues/comments"},{"label":"GitHub Docs: securely using pull_request_target, default policy","url":"https://docs.github.com/en/actions/reference/security/securely-using-pull_request_target"}],"publishedAt":"2026-10-22","updatedAt":"2026-10-23"}