gitlab_branch: Invalid resource ID format error when updating branch
Everyone can contribute. Help move this issue forward while earning points, leveling up and collecting rewards.
Bug Report
The gitlab_branch resource's Update function incorrectly reads the resource ID from the plan instead of state, causing an "Invalid resource ID format" error when updating branches. The ID is empty ('') in the plan during updates, but it should be read from state (as Read and Delete functions do).
This bug was introduced when migrating from SDK v2 to the Plugin Framework. The old SDK version correctly used d.Id() which reads from state, but the new Plugin Framework version reads from req.Plan instead of req.State. 28bb3739
Relevant Terraform Configuration
resource "gitlab_branch" "foo" {
count = var.foo == "foo" || var.bar ? 1 : 0
name = "foo"
ref = "master"
project = gitlab_project.project.id
keep_on_destroy = false
lifecycle {
ignore_changes = [
ref
]
}
}
Relevant Terraform Command
terraform plan
# or
terraform apply
Relevant Log Output
Error message:
Error: Invalid resource ID format
│
│ with module.project-example.gitlab_branch.foo[0],
│ on ../modules/foo/main.tf line 123, in resource "gitlab_branch" "foo":
│ 289: resource "gitlab_branch" "foo" {
│
│ The resource ID '' has an invalid format in Read. Error: Unexpected ID
│ format (""). Expected <part1>:<part2>
Terraform plan output:
# module.project-example.gitlab_branch.foo[0] will be updated in-place
~ resource "gitlab_branch" "foo" {
~ can_push = true -> (known after apply)
~ commit = [
- {
- author_email = "user@example.com" -> null
- author_name = "Example User" -> null
- authored_date = "2025-12-05T15:28:05Z" -> null
- committed_date = "2025-12-05T15:28:05Z" -> null
- committer_email = "user@example.com" -> null
- committer_name = "Example User" -> null
- id = "abc123def456..." -> null
- message = <<-EOT
Merge branch 'feature-branch' into 'foo'
...
EOT -> null
- parent_ids = [
- "parent1...",
- "parent2...",
] -> null
- short_id = "abc123de" -> null
- title = "Merge branch 'feature-branch' into 'foo'" -> null
},
] -> (known after apply)
~ default = true -> (known after apply)
~ developer_can_merge = true -> (known after apply)
~ developer_can_push = false -> (known after apply)
~ id = "12345678:foo" -> (known after apply)
+ keep_on_destroy = false
~ merged = false -> (known after apply)
name = "foo"
~ protected = true -> (known after apply)
~ web_url = "https://gitlab.com/group/project/-/tree/foo" -> (known after apply)
# (1 unchanged attribute hidden)
}
Expected behavior:
The Update function should read the ID from req.State (like Read and Delete do), not from req.Plan. The ID is immutable (computed from project and name which both have RequiresReplace()), so it should always be read from state.
Comparison with other functions:
-
Readfunction (line 241):req.State.Get(ctx, &data)✅ -
Deletefunction (line 309):req.State.Get(ctx, &data)✅ -
Updatefunction (line 276):req.Plan.Get(ctx, &data)❌
Old SDK v2 version (working):
The old version correctly used d.Id() which reads from state:
func resourceGitlabBranchUpdate(ctx context.Context, d *schema.ResourceData, meta any) diag.Diagnostics {
return resourceGitlabBranchRead(ctx, d, meta) // Read uses d.Id() from state
}
Additional Details
- GitLab Terraform Provider Version:
> 18.5.0 - GitLab Instance Version:
18.7.0-pre - Terraform Version:
OpenTofu v1.10.7 - License Tier:
enterprise