# create-pull-request: the default token is documented as unable to retrigger anything

> This GitHub action exists because a workflow can change files in its own workspace but cannot push them. It commits that state to a branch and opens a pull request, with more than twenty optional inputs, two of which are tokens, and a default token whose own documentation rules it out for two of the most common setups.

**peter-evans/create-pull-request** — A GitHub action to create a pull request for changes to your repository in the actions workspace

- Repository: https://github.com/peter-evans/create-pull-request
- Stars: 2,868 · Forks: 549
- Language: TypeScript
- License: MIT
- Published: 2026-09-28 · Updated: 2026-09-28 · Language: en
- Canonical page: https://hysenlabs.com/projects/peter-evans-create-pull-request

## The gap this fills is that a workflow cannot push what it just wrote

The premise is a single sentence about how Actions behave. Changes to a repository in the Actions workspace persist between steps in a workflow, which means a step can generate or modify files and leave them sitting in the checkout, and there is no way for a later step to turn that state into a commit on a real branch. This action is designed to sit alongside the steps that do the modifying and take over the last mile. It does three things in order. It checks the workspace for changes, and the check is deliberately broad: untracked new files, tracked modified files, and commits that were made during the workflow but never pushed. It then commits everything to a new branch, or updates the branch of a pull request that already exists. Finally it creates or updates a pull request merging that branch into the base, which defaults to whatever branch the workflow checked out. So the action is a publisher for workspace state, not a differ or a code generator.

## The default token is ruled out by its own documentation for two common setups

The token input defaults to the repository's own token, and the first thing the page does with that default is tell you when it will not work. There are two cases. If you want the pull requests this action creates to trigger a workflow on push or on pull request, you cannot use the default token at all, and the answer is a separate document rather than a flag to set. If you are using the default token and your repository was created after the second of February 2023, the default permission is read only, which is a platform change linked to GitHub's own changelog. Two more inputs inherit the same constraint. Requesting team reviewers needs a repository-scoped personal access token or equivalent application permissions. Commit signing differs depending on whether you use the built-in token, in which case commits are signed as the actions bot, or your own application token, in which case they are signed as your bot. There is also a second token input for the branch itself, which defaults to the value of the first.

## One repository setting has to be flipped before any of it works

Before the inputs, the page puts the prerequisite, and it is not a flag in the workflow file. For the action to work, you must explicitly allow GitHub Actions to create pull requests, and that setting lives in the repository's settings under Actions, then General, then Workflow permissions. The action does not request it, cannot detect it, and will not prompt for it. For repositories inside an organisation, the same setting is managed by administrators in the organisation's settings rather than by you, which makes it a dependency on someone else for most teams that are not using a personal account. This is the single most common reason a first attempt does nothing, and the page mentions it in a paragraph of its own between the usage example and the input table, which is where anyone scanning for configuration would miss it.

## More than twenty inputs, and every one of them has a documented default

The input table is the bulk of the documentation, and the page states up front that all inputs are optional with sensible defaults. Some defaults are self explanatory, such as the pull request title and the body text. Others encode decisions worth knowing about. The branch name defaults to a fixed value under a slash namespace, which is what makes the action update an existing pull request rather than opening a new one on every run. The committer defaults to the GitHub Actions bot with its numeric identifier embedded in the email address, while the author defaults to whoever triggered the workflow, with the actor identifier included, so a run started by a person is attributed to that person. Branch deletion is off, meaning a branch is left behind once its pull request closes. A sign-off line is off. Draft pull requests are off. Maintainer edit permission on the branch is on. And the base branch is not set at all, defaulting to the branch the workflow checked out.

The usage example is the smallest possible workflow:

```yml
      - uses: actions/checkout@v6

      # Make changes to pull request here

      - name: Create Pull Request
        uses: peter-evans/create-pull-request@v8
```

The action is referenced by a major version tag, and the page notes you can pin to an exact release in the usual dotted form instead.

## Two token inputs, two body inputs, and a fork target

Three pairs of related inputs are worth reading together. The token pair is the first: one token creates and updates the pull request, the other creates and updates the branch, and the second defaults to the first. Splitting them only matters when they need to differ, and the case the page describes is pushing to a fork, where the branch lands in a fork of the checked-out repository and the pull request is opened against the parent's base branch instead. The body pair is the second: a literal body string and a path to a file, with the file taking precedence, which is how you keep a long template out of the workflow file. The third group is the metadata list, labels, assignees, reviewers, team reviewers and milestone, each given as a comma or newline separated list, with the team reviewer input carrying its own token requirement. Commit signing is the fourth pairing, defaulting to off and behaving differently under the two token types.

## The committed bundle and the manifest's entry point do not match

The repository root has a distribution directory checked into it, which is how an action ships, since the runner does not install anything. That directory is the target of the bundler in the build script, which runs the TypeScript compiler and then the ncc bundler. The manifest, however, names a different path as its entry point, pointing at a file under a library directory that the build does not produce. Nothing breaks in practice, because an action is loaded from the distribution directory rather than resolved as a package, but it means the manifest field is describing a layout the project does not build, which is the kind of thing that misleads anyone importing the project as a library. The test setup has a similar shape. Unit tests are selected by passing a pattern to the test runner, and the integration tests are a shell script in the test directory, so running the full suite needs a POSIX shell on top of Node.

## Node 24 is required while the type definitions sit two majors behind

The manifest requires a Node version of 24.4.0 or later, which is a recent floor for an action that has been shipping for years. Alongside it, the development type definitions for Node are pinned to the 18 line, so the compiler checks code against a runtime six releases older than the one the engine field demands. The linting stack shows the same pattern in the other direction: a linter on its eighth major with the TypeScript plugin on 7 and the test plugin on 27, while the test runner itself is on 30. Nothing here suggests a problem, since type definitions lag deliberately, but the combination means the project is running a modern runtime against a conservative toolchain, which is the sort of gap that produces surprises when a newer definition catches something. The runtime dependencies are also worth a glance: the API client plugins include explicit retry and throttling, and a concurrency limiter is present, so the action is written to be polite about its own rate limits.

## Conclusion

Use this action when a workflow generates or edits files that a human should review before they land, since that is exactly the gap it fills. Three things decide whether it works on your repository. Whether workflow permissions have been switched on to allow the action to open pull requests, which is a repository or organization setting and the one hard prerequisite. Whether the default token is good enough, and the page says it is not if you want the resulting pull request to trigger further workflows, or if the repository was created after the February 2023 permission change that made the default read only. And whether you want one reusable branch or a new branch per run, which the branch and branch-suffix inputs decide. The default branch was last pushed on 2026-09-13 and the newest release is v8.1.1 from 2026-04-10.

## FAQ

### What is create-pull-request?

A GitHub action that takes changes sitting in a workflow's Actions workspace and publishes them. It checks for new files, modified files and commits made during the workflow that were never pushed, commits everything to a new branch or updates an existing pull request branch, then creates or updates a pull request merging that branch into the branch the workflow checked out.

### Why does create-pull-request need a different token?

The default is the repository's own token, and the page rules it out in two cases. If you want the created pull requests to trigger workflows on push or on pull request, the default token cannot do it. And if the repository was created after 2nd February 2023, the default token permission is read only. Requesting team reviewers also needs a repository-scoped personal access token or equivalent application permissions.

### How do I make create-pull-request commit only some files?

Use the add-paths input with a comma or newline separated list of paths written in git's pathspec syntax. The page is explicit about the fallback: if no paths are specified, all new and modified files are added. The path input is separate and sets which directory under the workspace is treated as the repository.

### How do I stop create-pull-request from reusing one branch forever?

The branch input defaults to a fixed name, and that fixed name is what makes the action update an existing pull request branch. To always get a new branch, use the branch-suffix input, whose valid values are random, timestamp and short-commit-hash, which is described as the alternative branching strategy. Branch deletion is a separate input and is off by default, so a branch is not removed when its pull request closes.

### Can create-pull-request open a draft pull request?

Yes, through the draft input, which accepts three values: true to create a draft only when the pull request is first opened, always-true to keep it a draft on both create and update, and false, which is the default. The body-path input also exists for reading the pull request body from a file, and it takes precedence over the inline body value.

## Sources

- [Issues](https://github.com/peter-evans/create-pull-request/issues)
- [License: MIT](https://github.com/peter-evans/create-pull-request/blob/main/LICENSE)
- [peter-evans/create-pull-request on GitHub](https://github.com/peter-evans/create-pull-request)
- [README](https://github.com/peter-evans/create-pull-request/blob/main/README.md)
- [Releases](https://github.com/peter-evans/create-pull-request/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/peter-evans-create-pull-request
