All skills
Skillintermediate

Terraform Troubleshooting & Best Practices

Common issues, security considerations, and best practices.

Claude Code Knowledge Pack7/10/2026

Overview

Terraform Troubleshooting & Best Practices

Common issues, security considerations, and best practices.

State Drift Issues

Some resources have known state drift. Add lifecycle blocks to prevent perpetual diffs:

ResourceDrift AttributesWorkaround
cloudflare_pages_projectdeployment_configs.*ignore_changes = [deployment_configs]
cloudflare_workers_scriptsecrets returned as REDACTEDignore_changes = [secret_text_binding]
cloudflare_load_balanceradaptive_routing, random_steeringignore_changes = [adaptive_routing, random_steering]
cloudflare_workers_kvspecial chars in keys (< 5.16.0)Upgrade to 5.16.0+
# Example: Ignore secret drift
resource "cloudflare_workers_script" "api" {
  account_id = var.account_id
  name = "api-worker"
  content = file("worker.js")
  secret_text_binding { name = "API_KEY"; text = var.api_key }
  
  lifecycle {
    ignore_changes = [secret_text_binding]
  }
}

v5 Breaking Changes

Provider v5 is current (auto-generated from OpenAPI). v4→v5 has breaking changes:

Resource Renames:

v4 Resourcev5 ResourceNotes
cloudflare_recordcloudflare_dns_record
cloudflare_worker_scriptcloudflare_workers_scriptNote: plural
cloudflare_worker_*cloudflare_workers_*All worker resources
cloudflare_access_*cloudflare_zero_trust_*Access → Zero Trust

Attribute Changes:

v4 Attributev5 AttributeResources
zonenamezone
account_idaccount.idzone (object syntax)
keykey_nameKV
location_hintlocationR2

State Migration:

# Rename resources in state after v5 upgrade
terraform state mv cloudflare_record.example cloudflare_dns_record.example
terraform state mv cloudflare_worker_script.api cloudflare_workers_script.api

Resource-Specific Gotchas

R2 Location Case Sensitivity

Problem: Terraform creates R2 bucket but fails on subsequent applies
Cause: Location must be UPPERCASE
Solution: Use WNAM, ENAM, WEUR, EEUR, APAC (not wnam, enam, etc.)

resource "cloudflare_r2_bucket" "assets" {
  account_id = var.account_id
  name = "assets"
  location = "WNAM"  # UPPERCASE required
}

KV Special Characters (< 5.16.0)

Problem: Keys with +, #, % cause encoding issues
Cause: URL encoding bug in provider < 5.16.0
Solution: Upgrade to 5.16.0+ or avoid special chars in keys

D1 Migrations

Problem: Terraform creates database but schema is empty
Cause: Terraform only creates D1 resource, not schema
Solution: Run migrations via wrangler after Terraform apply

# After terraform apply
wrangler d1 migrations apply <db-name>

Worker Script Size Limit

Problem: Worker deployment fails with "script too large"
Cause: Worker script + dependencies exceed 10 MB limit
Solution: Use code splitting, external dependencies, or minification

Pages Project Drift

Problem: Pages project shows perpetual diff on deployment_configs
Cause: Cloudflare API adds default values not in Terraform state
Solution: Add lifecycle ignore block (see State Drift table above)

Common Errors

"Error: couldn't find resource"

Cause: Resource was deleted outside Terraform
Solution: Import resource back into state with terraform import cloudflare_zone.example <zone-id> or remove from state with terraform state rm cloudflare_zone.example

"409 Conflict on worker deployment"

Cause: Worker being deployed by both Terraform and wrangler simultaneously
Solution: Choose one deployment method; if using Terraform, remove wrangler deployments

"DNS record already exists"

Cause: Existing DNS record not imported into Terraform state
Solution: Find record ID in Cloudflare dashboard and import with terraform import cloudflare_dns_record.example <zone-id>/<record-id>

"Invalid provider configuration"

Cause: API token missing, invalid, or lacking required permissions
Solution: Set CLOUDFLARE_API_TOKEN environment variable or check token permissions in dashboard

"State locking errors"

Cause: Multiple concurrent Terraform runs or stale lock from crashed process
Solution: Remove stale lock with terraform force-unlock <lock-id> (use with caution)

Limits

ResourceLimitNotes
API token rate limitVaries by planUse api_client_logging = true to debug
Worker script size10 MBIncludes all dependencies
KV keys per namespaceUnlimitedPay per operation
R2 storageUnlimitedPay per GB
D1 databases50,000 per accountFree tier: 10
Pages projects500 per account100 for free accounts
DNS records3,500 per zoneFree plan

See Also