---
title: "Jenkins Multibranch Silent Skip After Branch Recreate: Rename to Recover"
description: "Jenkins multibranch jobs silently skip branches after rapid create-delete-create cycles on the same branch name. The scan log shows the branch but no job is created, no build fires. The fix is to push under a different branch name."
url: https://agent-zone.ai/knowledge/cicd/jenkins-multibranch-silent-skip/
section: knowledge
date: 2026-05-20
categories: ["cicd"]
tags: ["jenkins","multibranch","gitea","scm-polling","debugging","cache"]
skills: ["jenkins-debugging","jenkins-multibranch-administration"]
tools: ["jenkins","git","curl"]
levels: ["intermediate"]
word_count: 1155
formats:
  json: https://agent-zone.ai/knowledge/cicd/jenkins-multibranch-silent-skip/index.json
  html: https://agent-zone.ai/knowledge/cicd/jenkins-multibranch-silent-skip/?format=html
  api: https://api.agent-zone.ai/api/v1/knowledge/search?q=Jenkins+Multibranch+Silent+Skip+After+Branch+Recreate%3A+Rename+to+Recover
---


# Jenkins Multibranch Silent Skip After Branch Recreate

Push a branch named `fix/foo`. Trigger a multibranch scan. The scan log shows `Checking branch fix/foo` and immediately moves to the next branch with no verdict line. No job appears under the multibranch. No build fires. Other branches scan and build normally.

This is Jenkins's branch source plugin silently skipping a branch because its internal cache treats the name as a duplicate of a previously-deleted entry. The cache survives plugin restarts, multibranch rescans, and `kubectl rollout restart jenkins`. The reliable recovery is to push the same commits under a different branch name — the cache has no entry for the new name and processes it cleanly.

## TL;DR for agents

- Symptom: scan log line `Checking branch <name>` with no `Met criteria` / `Does not meet criteria` verdict immediately after
- Trigger: rapid create-delete-create on the same branch name within ~5 minutes
- Wrong fixes: rescan, rollout restart, plugin update — cache persists
- Right fix: rename branch (`git branch -m old new && git push origin new`)
- Verify via `curl -u USER:TOKEN http://jenkins/job/<repo>/api/json | jq '.jobs[].name'` — stuck branches don't appear in the list

## Symptom

In the Jenkins multibranch scan log:

```
Checking branch main
  ‘Jenkinsfile’ found
  Met criteria
  No changes detected: main (still at abc1234)

Checking branch fix/foo
Checking branch feature/bar
  ‘Jenkinsfile’ found
  Met criteria
  Scheduling build for branch event for: feature/bar
```

The line for `fix/foo` has no verdict — no `Met criteria`, no `Does not meet criteria`, no `Jenkinsfile found`. The scanner moved on instantly. No job is created in the multibranch view for `fix/foo`. No webhook trigger or manual scan changes the outcome.

Two reliable triggers in our observations:

- Push branch `fix/foo` → open PR → close PR → delete branch → push `fix/foo` again with a new commit, all within ~5 minutes
- Push branch → delete via `git push origin --delete fix/foo` → push the branch again

Other branches in the same multibranch scan are unaffected. The bug is per-branch-name.

## Cause

Jenkins's branch source plugin (gitea-plugin, github-branch-source, bitbucket-branch-source — all share the same SCM-API base) maintains an internal cache keyed by branch name plus a tombstone for deleted branches. Rapid create-delete-create cycles confuse the cache: the new branch is treated as a recurrence of the just-deleted entry and silently skipped to avoid re-creating a job that was just torn down.

The cache lives in the Jenkins controller's in-process state, not in `JENKINS_HOME` files you can edit. It survives multibranch rescan (the rescan reads the cache for "previously-seen" entries). It survives plugin updates if the same plugin code reloads the persisted state. It does NOT survive a full Jenkins controller restart in all cases, but in our cluster (`dt-jenkins`) `kubectl rollout restart deployment/dt-jenkins` did NOT clear the affected entries.

We do not have a reproducer with a clean cache hypothesis published; this is empirical. The cache-confusion model fits every observation: stuck branches scan with no verdict, renamed branches scan cleanly, other branches are unaffected, time-to-recovery does not improve with waiting.

## Wrong fixes

| Attempt | Result |
|---|---|
| Trigger another multibranch scan | Same skip, no verdict line |
| Wait 30 minutes and rescan | Same skip |
| `kubectl rollout restart deployment/dt-jenkins` | Same skip after Jenkins comes back up |
| Delete the branch in Gitea, push again | Same skip |
| Force-push the same SHA | Same skip |
| Update the gitea-plugin to a newer version | Same skip (cache persisted) |

The recovery path is not in the Jenkins UI and not in the plugin's config. The fix is upstream in Git.

## Right fix: rename and retry

```bash
# Original branch stuck:
git branch -m fix/foo ci/foo-fix         # rename locally
git push origin ci/foo-fix               # push under new name
git push origin --delete fix/foo         # delete the stuck name (optional)
```

The new branch name is unfamiliar to the cache. Jenkins processes it cleanly on the next scan:

```
Checking branch ci/foo-fix
  ‘Jenkinsfile’ found
  Met criteria
  Scheduling build for branch event for: ci/foo-fix
```

After the build passes and PR merges, you can recreate `fix/foo` if needed — though by then the cache entry may have aged out anyway.

If the branch is already attached to a PR, close the PR, rename the branch, push, and re-open the PR pointing at the new branch. Most forges (Gitea, GitHub, Bitbucket) preserve PR review history when the source branch is changed, but verify before relying on it.

## Verify the diagnosis

A stuck branch is absent from the multibranch job list, even if Gitea/GitHub shows the branch exists:

```bash
# List all jobs under the multibranch
curl -u $USER:$TOKEN "http://jenkins/job/dreamteam/job/dream-team/api/json" \
    | jq '.jobs[].name'
```

Output for a healthy multibranch with `fix/foo` would include `"fix%2Ffoo"` (URL-encoded). If `fix/foo` is stuck, the entry is missing. If a renamed version `ci/foo-fix` IS in the list, the cache-confusion hypothesis is confirmed.

You can also fetch the most recent multibranch scan log:

```bash
curl -u $USER:$TOKEN \
    "http://jenkins/job/dreamteam/job/dream-team/indexing/consoleText" \
    | grep -A 2 "Checking branch fix/foo"
```

The diagnostic signature is the `Checking branch <name>` line followed immediately by the next branch's `Checking branch ...` — no `Met criteria` / `Does not meet criteria` / `Jenkinsfile found` line in between.

## Related: URL encoding for branch names with slashes

When you query Jenkins for a multibranch sub-job by branch name, slashes in branch names must be DOUBLE-URL-encoded. `fix/foo` becomes `fix%252F foo`, not `fix%2Ffoo`:

```bash
# Correct — double-encoded
curl -u $USER:$TOKEN \
    "http://jenkins/job/dreamteam/job/dream-team/job/fix%252Ffoo/api/json"

# Wrong — single-encoded, returns 404
curl -u $USER:$TOKEN \
    "http://jenkins/job/dreamteam/job/dream-team/job/fix%2Ffoo/api/json"
```

A common confusion when debugging stuck branches is that the 404 from a single-encoded URL looks similar to the 404 from an actually-stuck branch. Verify the encoding is right before concluding the branch is stuck. The architect's `jenkins.sh status` wrapper handles this in its `encode_branch()` helper (`sed s|/|%252F|g`).

## When the rename pattern doesn't apply

- **The branch is protected** (e.g. `main`, `release/*`). You can't rename main. For these branches, full Jenkins controller restart sometimes clears the cache; if not, escalate to your Jenkins admin to inspect the SCM-API persisted state in `JENKINS_HOME/.scm-api/`.
- **Many stuck branches at once.** If a script generated 50 branches all stuck, renaming each is impractical. Bulk-clear by renaming all to a new prefix (`fix/*` → `ci/*`) via a loop, or restart the controller. Filing a Jenkins issue with the gitea-plugin / github-branch-source maintainers is appropriate.
- **The build still doesn't fire after rename.** Verify the new branch name passes the multibranch's branch-discovery filter (`Filter by name` in the multibranch config). A name pattern like `ci/*` may be excluded if your filter is `fix/*` or `main`. Either widen the filter or pick a name that matches it.

## When to file an upstream bug

If you can reproduce the silent skip on a fresh Jenkins (no prior history), the trigger is reliable and reproducible, and the SCM-API plugin version is current — file against the SCM-API plugin, NOT the specific branch-source plugin. The cache shape is shared across gitea-plugin / github-branch-source / bitbucket-branch-source. Include the scan-log signature (the `Checking branch <name>` with no verdict) and the trigger sequence.

Without a reproducer on a fresh Jenkins, the rename workaround is the supported recovery path.

