## TL;DR
Terraform's "provider produced inconsistent result after apply" means the provider returned a different value for an attribute after creating the resource than it planned. This is usually a provider bug around computed attributes, but it is often triggered by your config: a value that changes between plan and apply (like a timestamp or random id used in two places), or a resource the provider normalizes. Pin the provider version, find the offending attribute in the error, and work around it with `lifecycle` or a data source.

## Error / query
```text
Terraform "provider produced inconsistent result" fix
```

## Use this skill when
- `terraform apply` fails with `Provider produced inconsistent result after apply`
- The error names a specific resource and attribute path like `.tags["Name"]`
- It started after a provider upgrade
- It happens intermittently on the same config

## Not for this skill when
- Plan and apply disagree because someone changed the config between them (re-run plan)
- The error is about a data source read during apply (different timing issue)
- State is locked or corrupted (state management, not provider consistency)
- You are writing a provider (this is consumer-side troubleshooting)

## Steps

### Step 1: Read which attribute was inconsistent
```bash
terraform apply 2>&1 | grep -B 5 -A 15 "inconsistent result"
```
Expected: the error names the resource address and the attribute path (e.g. `aws_instance.web: ... .user_data`). That attribute is the entire investigation.

### Step 2: Check whether a provider upgrade introduced it
```bash
grep -A 3 "required_providers" versions.tf 2>/dev/null; terraform version
git log --oneline -5 -- .terraform.lock.hcl
```
Expected: if the lockfile changed recently, try pinning the previous provider version and re-applying in a test workspace. Provider regressions on computed attributes are common enough to check first.

### Step 3: Look for values that legitimately change between plan and apply
```bash
grep -rn "timestamp()\|uuid()\|random_" --include="*.tf" . | grep -v ".terraform"
```
Expected: any use of `timestamp()`, `uuid()`, or random values feeding the inconsistent attribute. These produce a new value on every plan, so plan-time and apply-time never match; replace with a stable input variable.

### Step 4: Work around provider normalization with lifecycle
```bash
grep -B 5 -A 10 "lifecycle" [resource-file].tf
```
Expected: if the provider normalizes the value (case, ordering, defaults), add a `lifecycle { ignore_changes = [problem_attribute] }` block so Terraform stops fighting the provider over it. Confirm the ignored attribute is safe to ignore (tags and descriptions usually are; security settings are not).

### Step 5: Verify with a clean plan/apply cycle
```bash
terraform plan -out=tfplan && terraform apply tfplan
```
Expected: apply succeeds and a follow-up `terraform plan` shows no changes. If the inconsistency persists on the same attribute with a pinned provider, file it as a provider bug with the exact attribute path and a minimal config.

## Variant phrasings

### "terraform apply inconsistent result after apply"
Same error. The attribute path in the message is the starting point, step 1.

### "provider produced inconsistent final plan"
The plan-phase cousin: something changed between the plan and the final plan walk. Usually a data source read or a `timestamp()`; same step 3 hunt.

### "happens only sometimes on same terraform code"
Intermittent inconsistency points at ordering/normalization races in the provider or at eventually consistent APIs. Pin the provider version and retry; if it persists, it is a provider bug.

## Why it happens
Terraform's contract with providers: the value planned for an attribute must equal the value returned after apply. Providers break this when they compute or normalize attributes server-side (defaults filled in, ordering changed, case folded) and report the normalized value, or when the config feeds a value that is regenerated between plan and apply. Terraform cannot tell a benign normalization from real drift, so it errors.

## Edge cases and pitfalls
- `ignore_changes` on a security-relevant attribute (SG rules, IAM policies) hides real drift; scope it to the exact attribute path.
- Some providers need the attribute set explicitly to the normalized form (e.g. lowercase) instead of ignored; try setting the canonical value first.
- `terraform refresh`-only workflows can mask the inconsistency until the next apply; always verify with plan-after-apply.
- Provider bug reports need the minimal config and the exact inconsistent attribute; "it fails sometimes" without the attribute path gets closed.
- Do not "fix" it by tainting and recreating in a loop; if the provider normalizes on every create, recreation fails the same way.

## Provenance

Resolved from the public thread: https://vectle.com/posts/pst__cjYTBizoB0VVeLTy62OgQ
