Skip to main content
Release automation can advance the version manifest without ever creating the tag that goes with it. The workflow still reports success, so the repository looks healthy while it publishes nothing at all. Separately, the runner itself can be unavailable, in which case no workflow starts and no release happens for a reason that has nothing to do with the code. This page names both states, explains what causes them and gives the sequence that finishes a release by hand.

Signature

Three signals appear together. One alone is not conclusive, but all three at once mean the pipeline is wedged. Confirm it in one pass:
A version in the manifest with no matching tag on origin is the whole diagnosis.

Cause

Release Please decides what work remains from two places: the version in .release-please-manifest.json and the label on the release pull request. Merging the release pull request updates the manifest in the same commit, but creating the tag and the GitHub release is a separate step that runs afterwards. When that second step does not complete, the two disagree permanently. The manifest claims a version that was never tagged, and the pull request keeps its autorelease: pending label. Every later run finds the same merged pull request, decides the release is still outstanding, warns and stops. It never opens the next release pull request, so the repository silently stops releasing. Because docker-publish.yml runs only when release_created is true, no images are built either. Documentation that tells operators to pull a published tag then points at something that does not exist.

When no workflow starts at all

A wedged pipeline is a pipeline that ran. A different failure looks similar from the release page and is not the same thing: every job in every workflow fails within a few seconds with the annotation The job was not started because recent account payments have failed or your spending limit needs to be increased. Nothing ran, so nothing tagged, nothing published and no test result means anything.
Jobs that conclude in two or three seconds, across unrelated workflows, are the signature. Fix the billing state first. Release Please then resumes on the next push and needs none of the recovery below.

Releasing by hand while the runner is unavailable

Do this only when the release cannot wait for the billing fix, and run the full suite locally first, because no CI evidence exists for the commit.
Then bump the version everywhere Release Please would have. Eight files move together, and .release-please-manifest.json must agree with them or verify-release-state.sh fails the next Release run. pnpm check:release-versions reports any that were missed: Write the CHANGELOG.md section by hand in the same shape Release Please produces, then tag the release commit directly. There is no release pull request in this path, so take the commit that carries the version bump rather than looking one up:
Nothing needs relabelling, because no release pull request exists. Publishing the images cannot run until the runner is available, so they arrive late; say so in the release notes rather than leaving operators to discover that a documented tag does not resolve. Dispatch docker-publish.yml as described in step 4 of Recovery as soon as the runner works again.

Recovery

Run these in order, from an up to date main. Steps 1 and 2 are public and effectively irreversible, so verify the commit before pushing.
1

Tag the commit the release pull request merged

Take the merge commit of the release pull request, not the current tip of main. Everything after it belongs to the next release.
The ancestor check must print ancestor before you tag.
2

Create the release from the changelog section

Release Please already wrote the notes. Extract them rather than retyping them, so the release and the changelog cannot disagree.
--verify-tag fails rather than inventing a tag if the push in step 1 did not land.
3

Relabel the release pull request

This is what tells Release Please the release is finished. Without it the tool keeps reprocessing the same pull request and never proposes the next version.
4

Publish the images

docker-publish.yml accepts a manual dispatch with a tag input.
Both manifests must list linux/amd64 and linux/arm64.
5

Confirm the tool recovers

Merge any pull request into main, then check that a fresh release pull request opens for the next version and that the warning is gone.
A fresh release pull request proves the tool moved on. It does not prove the next release will tag itself: while the component mismatch above stands, that release wedges too and the guardrail fails the run again.
A recovery dispatch builds the tag you pass rather than the tip of main, and it publishes the same tag shapes a normal release does, including latest. Dispatching a version older than the newest published release therefore moves latest, 0 and the minor tag backwards onto it.Recover the newest release first, or accept that you have to re-dispatch the newest version afterwards to put the moving tags back. Verify the version tag resolves before you tell anyone to pull it.

The release pull request needs its workflows approved

A release pull request is opened by github-actions[bot], and its workflow runs land in the action_required state rather than starting on their own. main requires the checks, e2e, web-e2e and compose-smoke contexts, so until those runs are approved the release pull request reports no checks at all and cannot be merged. This looks like a wedged pipeline but is not one. Approve the waiting runs, let them finish, then merge:
Approving is preferable to merging with administrator privileges, because it runs the checks the branch rules ask for rather than skipping them.

Prevention

release.yml runs a verify-release-state job on every push that does not create a release. It asserts that the version in .release-please-manifest.json exists as a tag on origin and fails the workflow with an annotation when it does not. A wedged state that would otherwise report success stops the pipeline the first time it appears. ci.yml reports the same invariant as a warning on every pull request, so an author sees an unhealthy release pipeline before merging rather than after. A second failure shape has nothing to do with tags. Any file that states the version and is not listed in release-please-config.json stops moving with the release, so the release pull request carries a file that disagrees with the version it ships. The openapi document is the case that bites, because openapi-drift compares the captured info.version against the running API and reports a generic drift. pnpm check:release-versions runs in checks and names the file and the fix instead, and it fails the pull request that introduces an unregistered version rather than the release pull request months later.

Next steps

Run a published release

Which tags are published for each release, and how to pin one.

Troubleshooting

Symptoms a running instance produces, with causes and fixes.
Last modified on August 29, 2026