Retry a gitlab_group transfer while an earlier one is in progress

What does this MR do and why?

When parent_id of a gitlab_group changes, the update calls POST /groups/:id/transfer and then waits until the group reads the new parent_id. GitLab runs the transfer in the background (Groups::TransferService#schedule_async_transfer and Namespaces::Groups::TransferWorker), and the group reads its new parent before the worker has finished and left the transfer_in_progress state. A second transfer of the same group in that window is refused with 400 Unable to initiate transfer. The group may already have a transfer in progress. and nothing is scheduled, so the apply fails.

TestAccGitlabGroup_nested hits this intermittently: its last step moves the nested group again right after the previous step moved it, and the destroy after it fails as well. It failed this way on main on 2026-11-11 (EE 19.4.2, and CE and EE 19.5.0), and in recent merge request and merge train pipelines.

This MR asks for the transfer again while GitLab answers that refusal, within the resource's update timeout, as the delete already does for State cannot transition via "schedule deletion". Any other refusal fails as before. The REST group entity exposes no transfer state, and GraphQL has it only as Group.transferInProgress, an experiment since 19.3, which the provider does not use under its policy on experimental features, so the wait after the transfer still checks only parent_id.

Related to https://gitlab.com/gitlab-org/terraform-provider-gitlab/-/pipelines/3052610718 and https://gitlab.com/gitlab-org/terraform-provider-gitlab/-/pipelines/3053133207

How to verify

The race depends on timing, so no test can produce it on demand. TestAccGitlabGroup_transferWhileAnEarlierTransferRuns comes closest: it moves the group outside of Terraform, waits until the group reads its new parent, as the provider does after a transfer, and then lets Terraform move it back. Without this change it fails with that 400 whenever GitLab has not finished the first move by the time Terraform asks, which is how TestAccGitlabGroup_nested fails in CI.

make testacc-up
make testacc RUN=TestAccGitlabGroup_transferWhileAnEarlierTransferRuns
make testacc RUN=TestAccGitlabGroup_nested
What I ran (GitLab EE 19.5.3 unlicensed, Go 1.26.10, Terraform 1.4.0, golangci-lint 2.15.0)
  • Against a GitLab started with make testacc-up SERVICE=gitlab-ee, with the REST API alone: I transferred a subgroup, waited until GET /groups/:id read the new parent_id (about 10 seconds), and transferred it straight back. GitLab answered 400 {"message":"Unable to initiate transfer. The group may already have a transfer in progress."} and accepted the same request at the fourth try, 10 seconds later. A transfer 3 seconds after the group read its parent back was refused the same way.
  • TestAccGitlabGroup_transferWhileAnEarlierTransferRuns failed 1 of 3 times on main with the error CI shows. In the two runs that passed, GitLab accepted the transfer back less than 4 seconds after the step began, so the first move had already finished. With this change it passed 5 times in 5 runs, and the provider asked for the transfer again 6 times in all.
  • TestAccGitlabGroup_nested passed 3 times on main and 5 times with this change on that instance. The debug log of the runs on main shows no refusal, so the race did not occur there.
  • make build, go vet (also with -tags acceptance), gofmt -s, make lint-golangci (0 issues), make lint-tfprovider, make lint-examples-sh, make lint-examples-tf, make lint-custom, make generate (no diff) and make test are clean.

This work comes from maintaining gitlab-mcp-server, whose upstream-bugs.md records everything done on its dependencies and sibling projects.

Merge request reports

Loading
Loading