Skip to content
Latchkey

Neon "branch already exists" (create branch per PR) in CI

Neon refuses to create a branch whose name is already taken. When you create a branch per pull request, a re-run of the same PR hits the branch left by the first run. Either reset the existing branch or make creation idempotent.

What this error means

A "neonctl branches create" step fails with "branch with name pr-123 already exists" on the second push to a PR, because the first run already created it.

neonctl
ERROR: branch with name "pr-123" already exists in project "cool-project-12345"

Common causes

The per-PR branch persists across pushes

Each push to the PR re-runs the workflow, but the branch created on the first push is still there, so a plain create collides.

A previous run failed before cleanup

A run that errored after creating the branch never deleted it, leaving the name occupied for the retry.

How to fix it

Reset the branch if it exists, else create it

  1. Try to reset the PR branch to parent; if it does not exist, create it.
  2. Use a deterministic name like pr-<number> so the same PR maps to the same branch.
  3. Delete the branch in a cleanup job when the PR closes.
Terminal
BR="pr-${{ github.event.number }}"
neonctl branches reset "$BR" --project-id "$NEON_PROJECT_ID" \
  || neonctl branches create --name "$BR" --project-id "$NEON_PROJECT_ID"

Clean up the branch when the PR closes

Add a job triggered on pull_request closed that deletes the branch so names never accumulate.

.github/workflows/neon-cleanup.yml
on:
  pull_request:
    types: [closed]
jobs:
  cleanup:
    steps:
      - run: neonctl branches delete "pr-${{ github.event.number }}" --project-id "$NEON_PROJECT_ID"

How to prevent it

  • Name each per-PR branch deterministically so reruns are idempotent.
  • Reset an existing branch instead of always creating a new one.
  • Delete the branch on PR close to avoid leftover names and cost.

Related guides

Tired of flaky CI? Latchkey auto-heals failed jobs and retries them for you. Start free →