Skip to content

Forgejo and Gitea reviewer picker repeats the same assignees over and over #23575

Closed

Description

@0pilatos0

What happened

When selecting reviewers on a Forgejo pull request, the same 2 reviewers loop over and over in the picker: user-a, user-b, user-a, user-b, ... for the whole list. Selecting one works (every copy of that user shows the check mark), but the list is hundreds of rows long and takes about 8 seconds to load.

Diagnosis

listReviewerCandidates in the Forgejo provider loads /repos/{owner}/{repo}/assignees through the generic page() helper (packages/source-control-forgejo/src/server/ForgejoPullRequestProvider.ts:549). page() keeps asking for ?limit=50&page=N until readPage says there are no more pages, or until it has 500 items (:141-152).

readPage decides whether there is a next page like this (:137):

more: rows.length > 0 && (links === undefined || /rel="?next"?/i.test(links)),

So a response with rows and no Link header counts as "there is another page". With fj credentials, ForgejoCli.requestFj writes a link: line only when Forgejo sends one (ForgejoCli.ts:407).

Forgejo's /assignees endpoint is not paginated. GetAssignees (routers/api/v1/repo/collaborators.go in Forgejo) ignores page/limit, returns every assignee in one response and sets no Link header. Every page therefore returns the same full list, more stays true, and the loop only stops at the 500-item cap.

In this case the repo has 3 assignees: 167 requests × 3 = 501 items, truncated: true. After the PR author is filtered out, the picker shows the other 2 users about 167 times each.

The other page() callers (commit statuses, PR commits, reviews, reactions, labels) hit endpoints that do paginate on the Forgejo side, so they end at the first empty page. Only /assignees is affected.

Possible fix direction: read /assignees once (it's a plain unpaginated list, readArray fits), and/or stop treating a missing Link header as "more pages" when the page came back with fewer than limit rows.

Steps to reproduce

  1. Self-hosted Forgejo (seen on 17.0.0+gitea-1.22.0) with a repo where 2 or more users besides you have write access. T3 Code is signed in to it through an fj login.
  2. In T3 Code, open a pull request in that repo and go to the Summary tab.
  3. Next to Reviewers, click the add-reviewer button.
  4. Expected: each assignee once. Actual: after a few seconds, the same users repeat for hundreds of rows. The server trace shows GET .../assignees?limit=50&page=1 through page=167 for one open of the picker.

Version

0.1.2-nightly.20261022.3512 (desktop app with its local server; main has the same code as of 2026-10-22)

Environment

macOS (Darwin 27.0.0, arm64), T3 Code desktop nightly, Forgejo 17.0.0+gitea-1.22.0 (self-hosted, fj login)

Evidence

# server.trace.ndjson, one opening of the reviewer picker (host and repo redacted)
13:34:48 -> 13:34:56  GET https://forgejo.example.com/api/v1/repos/<owner>/<repo>/assignees?limit=50&page=1 ... page=167
                      167 requests, all http.response.status_code 200, ~8 s total
13:34:48  ForgejoPullRequestProvider.listReviewerCandidates  durationMs=8075  exit=Success
13:34:48  ws.rpc.pullRequests.reviewerCandidates             durationMs=8234  exit=Success

# Forgejo GetAssignees (routers/api/v1/repo/collaborators.go): no ListOptions, no SetLinkHeader
assignees, err := repo_model.GetRepoAssignees(ctx, ctx.Repo().Repository)
...
ctx.JSON(http.StatusOK, convert.ToUsers(ctx, ctx.Doer(), assignees))

Related issues

#23551 is also about Forgejo/Gitea API paging cost, but it covers PR lookups by branch, not reviewer candidates. No existing issue covers this.

Fix applied or workaround

Nothing changed on the machine. Workaround: pick the reviewer from the top of the list (selection works), or request reviewers in the Forgejo web UI.

Filed by

Claude Code (claude-opus-5-5) via t3 triage

Activity

  1. changed the title [-]Forgejo reviewer picker repeats the same assignees over and over[/-] [+]Forgejo and Gitea reviewer picker repeats the same assignees over and over[/+] on Oct 25, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions