TerraformPilot

Troubleshooting

Fix Terraform Error - GCP IAM Member Already Exists

Fix Google Cloud IAM binding conflicts in Terraform. Covers authoritative vs non-authoritative bindings, member format, conditions, and import patterns.

LLuca Berton2 min read

Quick Answer

#

The IAM binding already exists — either created manually or by another Terraform resource. Use google_project_iam_member (non-authoritative) instead of google_project_iam_binding (authoritative) to avoid conflicts, or import the existing binding.

The Error

#
Error: Error applying IAM policy for project "my-project":
  Error setting IAM policy: googleapi: Error 409:
  There were concurrent policy changes. Please retry the whole read-modify-write.
Error: Member already has the requested role on resource

What Causes This Error

#

1. Authoritative vs Non-Authoritative Resources

#

GCP Terraform provider has three IAM resource types with different behavior:

ResourceBehaviorRisk
google_project_iam_policySets entire policy — removes all other bindings⚠️ Dangerous
google_project_iam_bindingAuthoritative for one role — removes other members of that role⚠️ Careful
google_project_iam_memberNon-authoritative — adds one member to one role✅ Safe

2. Concurrent Modifications

#

Multiple Terraform runs or manual Console changes happening at the same time.

3. Duplicate Member Resources

#

Two Terraform resources adding the same member to the same role.

How to Fix It

#

Solution 1: Use google_project_iam_member (Non-Authoritative)

#
# SAFE — adds a single binding without affecting others
resource "google_project_iam_member" "editor" {
  project = var.project_id
  role    = "roles/editor"
  member  = "serviceAccount:${google_service_account.terraform.email}"
}
 
resource "google_project_iam_member" "viewer" {
  project = var.project_id
  role    = "roles/viewer"
  member  = "user:developer@example.com"
}

Solution 2: Import Existing Bindings

#
# Import a member binding
# Format: "project_id role member"
terraform import google_project_iam_member.editor \
  "my-project roles/editor serviceAccount:terraform@my-project.iam.gserviceaccount.com"

Solution 3: Handle Concurrent Policy Changes

#
# Add retry logic with lifecycle
resource "google_project_iam_member" "ci_deployer" {
  project = var.project_id
  role    = "roles/run.admin"
  member  = "serviceAccount:${var.ci_sa_email}"
 
  # Terraform automatically retries concurrent policy conflicts
}

Solution 4: Fix Member Format

#
# Member format must be one of:
# user:email@example.com
# serviceAccount:sa@project.iam.gserviceaccount.com
# group:group@example.com
# domain:example.com
 
# BAD
member = "terraform@my-project.iam.gserviceaccount.com"
 
# GOOD
member = "serviceAccount:terraform@my-project.iam.gserviceaccount.com"

When to Use Each IAM Resource

#
  • iam_member: Adding individual bindings — safe, no side effects
  • iam_binding: You want to control ALL members of a specific role — removes members not in your config
  • iam_policy: You want to control the ENTIRE IAM policy — removes everything not in your config (dangerous)

Troubleshooting Checklist

#
  1. ✅ Are you using iam_member (safe) or iam_binding (authoritative)?
  2. ✅ Is the member format correct? (user:, serviceAccount:, group:)
  3. ✅ Is another Terraform run modifying IAM concurrently?
  4. ✅ Do you have duplicate resources for the same member+role?

Prevention Tips

#
  • Default to google_project_iam_member — safest option, no side effects
  • Never use google_project_iam_policy unless you manage ALL IAM for the project
  • Use consistent member formats — always include the type prefix
  • Avoid mixing iam_binding and iam_member for the same role
#

Conclusion

#

GCP IAM conflicts usually come from using authoritative resources (iam_binding or iam_policy) that overwrite existing bindings. Use google_project_iam_member for safe, non-authoritative additions, verify member format includes the type prefix, and import existing bindings rather than recreating them.

#Terraform#Google Cloud#Troubleshooting#Error Fix

Share this article