Terraform plan drift on genesyscloud_routing_queue - state lock issue

Can anyone clarify why terraform plan keeps flagging drift on genesyscloud_routing_queue despite matching state? getting 409 on lock acquisition during refresh. docs say “state locking prevents concurrent modifications to the state file” but i’m the only one running applies.

{
 "name": "Priority Support",
 "description": "High tier queue",
 "outbound_email": "[email protected]"
}

plan insists outbound_email changed to null. state lock file seems stuck in tmp dir.

I normally fix this by bypassing the default backend locking if you’re running locally or in a CI pipeline without a shared state file configured properly. the 409 isn’t always a concurrency issue; sometimes it’s a stale lock file left behind by a crashed process.

check your .terraform directory. if you see a terraform.tfstate.lock.info file, delete it. that’s likely your culprit.

if you’re using S3 or Azure Blob storage for state, ensure your IAM role has s3:DeleteObject permissions on the lock key. without that, terraform can’t release the lock after a refresh, causing subsequent plans to fail with 409.

also, make sure you’re not accidentally running terraform refresh in parallel. even if it’s just you, a background CI job might be holding the lock.

# force unlock if you're sure no one else is applying
terraform force-unlock <lock-id>

grab the lock ID from the error message. it’s usually a long hex string.

this is a common gotcha when moving from local dev to remote state. the drift you’re seeing on genesyscloud_routing_queue is probably just terraform re-reading the state while the lock is contested, not actual config drift.

once the lock is cleared, run terraform plan again. if the drift persists, check if your queue name has trailing spaces or if the API is returning a different outbound_email format than your HCL.

i’ve seen this break builds in the middle of the night. annoying, but easy to fix once you know where the lock file is hiding.

resource “genesyscloud_routing_queue” “priority_support” {
name = “Priority Support”
description = “High tier queue”
outbound_email = “[email protected]”

Explicitly ignore computed or server-side managed attributes

lifecycle {
ignore_changes = [
member_count,
wrap_up_timeout,
enabled
]
}
}

Verify your token has the right scopes

curl -X GET “https://api.mypurecloud.com/api/v2/authorization/oauth/userinfo
-H “Authorization: Bearer YOUR_TOKEN”

deleting the lock file is a band-aid. if you're the only one running applies, a stale lock usually means a previous run crashed mid-update. but the drift you're seeing? that's likely Genesys Cloud's server-side defaults clashing with your Terraform state.

the provider pulls back a full object on refresh. if you don't specify `wrap_up_timeout` or `enabled` in your config, GC sets them to defaults (usually 0s and true). Terraform sees those values in the remote state vs your empty local config and flags drift.

add the `lifecycle { ignore_changes }` block above for any attribute you don't explicitly manage. this tells TF to stop caring if GC changes it.

also, check your API scope. if your service account lacks `routing:queue:view`, the provider might fail to fetch the full resource details, leading to a partial state read. that partial read looks like drift.



look for `"routing:queue:view"` in the scopes list. if it's missing, grant it and rerun `terraform refresh`.

i've seen this pattern constantly in CI pipelines. the lock 409 is just noise. the real issue is always schema mismatch or missing read permissions. fix the config, fix the perms, lock goes away.

Check your backend configuration first, as the 409 lock error often hides a deeper issue with how the state is being read from S3 or Azure Blob storage. while deleting the lock file works temporarily, it’s usually a symptom of a stale lease or a network timeout during the initial refresh. if you’re using a remote backend, ensure your IAM role has s3:GetObject and dynamodb:GetItem permissions explicitly defined for the state bucket. missing these can cause the lock acquisition to hang until it times out, triggering the 409. also, verify that the encrypt flag is set to true in your backend block if you’re using S3, as unencrypted state files sometimes cause unexpected drift detection logic to fail silently.

the drift itself is likely coming from attributes that Genesys Cloud manages server-side or computes dynamically. the genesyscloud_routing_queue resource has several fields that don’t map directly to the input payload, like member_count or status. terraform sees these as changes because the API returns them, but you didn’t declare them in your config. you need to add a lifecycle block to ignore these computed values. without this, every plan will show a diff even if nothing actually changed in your code. this is a common gotcha with the Genesys provider, especially for routing resources where the backend adds metadata automatically.

here’s how you should structure the resource to stop the noise. notice the ignore_changes array. it tells terraform to stop caring about those specific fields during plan and apply. this keeps your state file clean and prevents false positives.

resource "genesyscloud_routing_queue" "priority_support" {
 name = "Priority Support"
 description = "High tier queue"
 outbound_email = "[email protected]"

 lifecycle {
 ignore_changes = [
 member_count,
 status,
 last_updated_by_id,
 last_updated_date
 ]
 }
}

run terraform refresh after adding this. it should clear the phantom drift. if you still see issues, check the API response directly using GET /api/v2/routing/queues/{id} to see what fields are actually populated by the platform. sometimes the provider version is outdated and doesn’t match the API schema.