SIP Trunk 409 Conflict during Terraform Apply

How should I properly to handle SIP Trunk 409 Conflict in Terraform?

Applying genesyscloud_sip_trunk resource fails with HTTP 409 Conflict. Provider is genesyscloud v1.22.0 on AU-1 BYOC environment.

Terraform attempts to create the trunk, but API returns duplicate resource error. The trunk exists in the platform but is not tracked in state file. This happens after a failed deployment or manual deletion in UI without corresponding state removal.

Current configuration:

resource "genesyscloud_sip_trunk" "main" {
 name = "Prod-SIP-Trunk-01"
 description = "Primary SIP Trunk for Australia"
 
 auth_mode = "none"
 
 domain = "sip.carrier.com"
 
 enabled = true
 
 sip_uri = "sip:sip.carrier.com"
 
 endpoints {
 host = "10.20.30.40"
 }
 
 inbound {
 enabled = true
 
 dialplan {
 name = "Global-Dialplan"
 description = "Default Inbound"
 }
 }
 
 outbound {
 enabled = true
 
 dialplan {
 name = "Global-Dialplan"
 description = "Default Outbound"
 }
 }
}

Error output:

Error: API returned an error: 409 Conflict
Body: {
 "errors": [
 {
 "code": "duplicate_resource",
 "message": "SIP Trunk with name 'Prod-SIP-Trunk-01' already exists"
 }
 ]
}

Manual workaround is to import the resource into state. However, this breaks CI/CD pipeline automation. Need a way to force import or handle this conflict automatically during terraform apply.

Is there a lifecycle hook or provider flag to ignore existing resources and update instead? Or should we rely on terraform import script in GitHub Actions?

Environment details:

  • Genesys Cloud Platform: AU-1 BYOC
  • Terraform Provider: genesyscloud v1.22.0
  • Terraform Version: 1.5.7
  • GitHub Actions: ubuntu-latest

Looking for best practice to manage this drift between platform state and Terraform state for SIP Trunks.

If I remember correctly, you just need to run terraform import to pull that orphaned trunk into your state file. don’t try to force-create it again or you’ll break the config.

have you tried checking the actual HTTP response body before just importing? a 409 conflict usually means the name already exists, but sometimes it’s a validation error that gets masked as a conflict if you’re not looking closely. importing is fine if the resource truly exists and matches your config, but if the existing trunk has different settings (like different SIP domains or TLS configs), importing it will just make terraform think it’s happy when it’s actually drifted.

better approach: delete the orphaned trunk manually in the Admin UI first. yes, it’s annoying, but it clears the slate. then run terraform apply. if you can’t delete it because it’s in use, you have to find out what’s using it. usually it’s a routing rule or a site config. check the SIP Trunk usage endpoints.

here’s a quick way to check if the trunk is referenced elsewhere via the API:

curl -X GET "https://api.eu1.genesys.cloud/api/v2/communications/sip/trunks/{trunkId}/usage" \
 -H "Authorization: Bearer $TOKEN"

if that returns empty, you’re good to delete. if it returns a list, you need to remove those references first. the docs for this are a bit sparse, but the endpoint is documented here: Genesys Cloud Developer Center

also, check your terraform state file manually. sometimes terraform state list shows it, but terraform plan doesn’t catch the drift if the ID changed. if you’re sure it’s an orphan, terraform import works, but you’ll need to match the exact ID. get the ID from the UI by clicking the trunk and looking at the URL.

don’t rush this. sip trunks are tricky with BYOC environments. if you force-create, you might end up with two trunks with the same name but different IDs, which breaks your routing logic later. better to clean up the mess properly now.

ah, this is a known issue with the provider. just run terraform import genesyscloud_sip_trunk.name <id> to sync state. if the config drifts, you’ll get errors on the next apply. make sure the sip domain matches exactly.

if i remember correctly, the 409 is just the API yelling that the resource id is already taken in the backend. terraform import is the right move, but you gotta be careful with the sip_domain attribute. if the imported state doesn’t match your .tf file exactly, the next apply will try to update it and fail again because SIP trunks are picky about domain bindings.

we’ve seen this on AU-1 BYOC where manual UI changes leave ghost configs. run terraform import genesyscloud_sip_trunk.my_trunk <trunk_id>. then do a terraform plan. if it shows changes, check the sip_domains list. sometimes the UI adds a default domain that isn’t in your code. you’ll need to add that domain to your tf or remove it from the trunk in UI before re-importing. don’t ignore the drift. it’ll bite you later when you try to deploy a new trunk with the same domain.