Skip to content

GitLab SCM Provider generator discards collected branches on a mid-pagination 404 which can prune Applications #29323

Description

@nitishfy

Checklist:

  • I've searched in the docs and FAQ for my answer: https://bit.ly/argocd-faq.
  • I've included steps to reproduce the bug.
  • I've pasted the output of argocd version.

Describe the bug

GitlabProvider.listBranches treats 404 as no branches inside its pagination loop and returns an empty slice with a nil error that throws away every branch already collected from earlier pages.

for {
		gitlabBranches, resp, err := g.client.Branches.ListBranches(repo.RepositoryId, opt)
		// 404s are not an error here, just a normal false.
		if resp != nil && resp.StatusCode == http.StatusNotFound {
			return []gitlab.Branch{}, nil
		}
		if err != nil {
			return nil, err
		}
		for _, gitlabBranch := range gitlabBranches {
			branches = append(branches, *gitlabBranch)
		}

		if resp.NextPage == 0 {
			break
		}
		opt.Page = resp.NextPage
	}
	return branches, nil
}

This matters because the appset reconciler trusts nil error completely. A returned error is safe however, a successful empty result flows straight through to prune step so a repo with more than 100 branches that has 404s on page 2 can have all of its generated apps deleted rather than the generator failing and retrying. Interestingly, GitLab returns 404 rather than 403 for a project the token can't see so a token whose project access is revoked in the middle can hit this.

To Reproduce

This is a race against the GitLab API, so the deterministic reproduction is at the unit level.

  1. Stand up an httptest server for /api/v4/projects/{id}/repository/branches that returns
    a full page of 100 branches with X-Next-Page: 2, then 404 for page=2.
  2. Call listBranches with allBranches: true.
  3. Observe it returns ([], nil) - the 100 branches from page 1 are gone, and there is no error.

Expected behavior

A 404 encountered while paginating should be returned as an error, so the reconciler records an ErrorOccurred condition and requeues with existing Applications untouched.

Screenshots

N/A

Version

argocd: v3.5.1+109ca7c
  BuildDate: 2026-08-12T11:51:48Z
  GitCommit: 109ca7ca71139e514114499d294a492e7910a965
  GitTreeState: clean
  GoVersion: go1.26.4
  Compiler: gc
  Platform: darwin/arm64
argocd-server: v3.5.1
  BuildDate: 2026-08-12T11:28:06Z
  GitCommit: 109ca7ca71139e514114499d294a492e7910a965
  GitTreeState: clean
  GitTag: v3.5.1
  GoVersion: go1.26.4
  Compiler: gc
  Platform: linux/arm64
  Kustomize Version: v5.8.1 2026-02-09T16:15:27Z
  Helm Version: v4.2.1+gd591a19
  Kubectl Version: v0.36.1
  Jsonnet Version: v0.22.0

Logs

Paste any relevant application logs here.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

bugSomething isn't workingbug/priority:urgentBug should be fixed immediatelybug/severity:criticialA critical bug in ArgoCD, possibly resulting in data loss or severe degraded overall functionalitycomponent:application-setsIssue related to the ApplicationSet controllertriage/pendingThis issue needs further triage to be correctly classified

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions