Terraform Error Guide: 'Provider produced inconsistent final plan' on apply
Fix Terraform's 'Provider produced inconsistent final plan' error: identify provider bugs, computed-attribute drift, version mismatches, and unstable expressions.
- #terraform
- #troubleshooting
- #errors
- #providers
Overview
Provider produced inconsistent final plan is a consistency check failure inside Terraform. During apply, Terraform re-runs the plan against the provider and compares the result to the plan it showed you. If the provider now reports a different value for an attribute than it promised at plan time, Terraform aborts rather than apply something you never reviewed. It is almost always a provider-side bug or a value the provider could not predict.
You will see this on terraform apply:
Error: Provider produced inconsistent final plan
When expanding the plan for aws_lb_target_group.app to include new values
learned so far during apply, provider "registry.terraform.io/hashicorp/aws"
produced an invalid new value for .name: was cty.StringVal("app-tg-a1b2c3d4"),
but now cty.StringVal("app-tg-9f8e7d6c").
This is a bug in the provider, which should be reported in the provider's own
issue tracker.
The message names the resource, the attribute (.name), and the planned vs. final values. Terraform explicitly says it is a provider bug — your job is to find the provider/version or expression that triggers it and work around it.
Symptoms
applyfails withProvider produced inconsistent final planafter a clean plan.- The message gives an attribute with
was <X>, but now <Y>. - It mentions “This is a bug in the provider”.
- It appears after a provider version bump, or on resources using random/computed defaults.
terraform apply
Error: Provider produced inconsistent final plan
.tags: element "ManagedBy" has vanished
This is a bug in the provider, which should be reported in the provider's own
issue tracker.
Common Root Causes
1. A known provider bug at the current version
The provider version mishandles a computed attribute; a newer (or specific older) version fixes it.
terraform version
grep -A3 required_providers versions.tf
Terraform v1.7.5
on linux_amd64
+ provider registry.terraform.io/hashicorp/aws v5.31.0
Checking the provider’s changelog/issues for the named attribute often shows a fix in a later patch.
2. A computed attribute the provider mispredicts
Attributes the API assigns (ARNs, generated names, default tags) are sometimes guessed at plan time and corrected during apply.
terraform plan 2>&1 | grep -A2 'name '
name = "app-tg-${random_id.suffix.hex}"
A name partly derived from a computed value can shift between plan and apply.
3. default_tags interacting with resource tags
AWS provider default_tags merged with per-resource tags is a classic source of “element has vanished / appeared” inconsistencies.
grep -rn 'default_tags' provider.tf
provider "aws" {
default_tags {
tags = { ManagedBy = "terraform" }
}
}
When the same key appears in both default_tags and a resource’s tags, some versions produce inconsistent final tags.
4. An unstable or non-deterministic expression
An expression that evaluates differently between plan and apply (e.g. timestamp(), ordering of a for/merge) can change a value mid-apply.
grep -rn 'timestamp()\|uuid()\|merge(' *.tf
tags = merge(var.tags, { created = timestamp() })
timestamp() returns a new value on apply, changing the attribute the provider planned.
5. Provider/Terraform version mismatch
A Terraform core version paired with a provider SDK version that disagree on a type/shape can trip the consistency check.
terraform providers
provider[registry.terraform.io/hashicorp/aws] ~> 5.31
provider[registry.terraform.io/hashicorp/random] ~> 3.5
Bumping or pinning to a tested combination often resolves it.
6. A resource whose API changed shape
The upstream API started returning a field differently (new default, reordered list), and the provider has not caught up.
terraform plan 2>&1 | grep -A2 'vanished\|appeared'
.ingress: block count changed from 2 to 1
A set/list the API normalizes can mismatch the planned count.
Diagnostic Workflow
Step 1: Capture the exact resource and attribute
terraform apply 2>&1 | grep -A4 "inconsistent final plan"
Record the resource address, the attribute path, and the was/now values.
Step 2: Note your Terraform and provider versions
terraform version
These two numbers are what you will check against the provider’s issue tracker/changelog.
Step 3: Inspect the attribute’s expression
grep -rn '<ATTRIBUTE>' *.tf
Look for computed inputs, timestamp()/uuid(), or default_tags/tags overlap feeding the attribute.
Step 4: Try a targeted re-apply
terraform apply -target=<ADDRESS>
Many inconsistencies are transient on second apply because the computed value is now known and stored in state.
Step 5: Pin or bump the provider, then re-plan
# edit versions.tf to a known-good version, then:
terraform init -upgrade
terraform plan
Move to a provider version where the named attribute bug is fixed, and confirm the plan is clean.
Example Root Cause Analysis
A deploy fails on apply right after a clean plan:
Error: Provider produced inconsistent final plan
When expanding the plan for aws_instance.app to include new values learned so
far during apply, provider "registry.terraform.io/hashicorp/aws" produced an
invalid new value for .tags_all: new element "ManagedBy" has appeared.
The attribute is tags_all, and ManagedBy is appearing during apply. Checking the provider config:
grep -rn 'default_tags\|tags ' provider.tf main.tf
provider.tf: default_tags { tags = { ManagedBy = "terraform" } }
main.tf: tags = { Name = "app" }
The provider version in use mishandles the merge of default_tags.ManagedBy into the resource’s tags_all — a known consistency bug on this minor version. The plan computes tags_all without ManagedBy, then apply adds it back.
Fix: bump the AWS provider to a patch where the default_tags/tags_all merge is fixed.
# versions.tf: aws = { version = "~> 5.40" }
terraform init -upgrade
terraform apply
With the newer provider, tags_all is computed consistently and the apply completes.
Prevention Best Practices
- Pin provider versions (
~>) and bump deliberately; test a new provider version in a non-prod workspace before rolling it out. - Keep expressions deterministic — avoid
timestamp()/uuid()in attributes the provider must predict; useignore_changesif a value must drift. - Avoid overlapping keys between
default_tagsand per-resourcetags; pick one place to set each tag. - When you hit this, search the provider’s issue tracker for the exact attribute name and
was/nowpattern — most are known bugs with a fixed version. - Run apply once more (or
-target) for transient computed-value cases before assuming a deeper bug. - For triage, the free incident assistant can extract the resource/attribute and suggest a version-pin or expression fix. More patterns in the Terraform guides.
Quick Command Reference
# Capture the failing resource and attribute
terraform apply 2>&1 | grep -A4 "inconsistent final plan"
# Record versions (needed to search the issue tracker)
terraform version
# Inspect the attribute's expression
grep -rn '<ATTRIBUTE>' *.tf
# Look for default_tags / unstable functions
grep -rn 'default_tags\|timestamp()\|uuid()' *.tf
# Try a targeted re-apply (transient computed values)
terraform apply -target=<ADDRESS>
# Pin/bump the provider then re-plan
terraform init -upgrade && terraform plan
Conclusion
Provider produced inconsistent final plan is Terraform catching the provider returning a value at apply time that differs from the plan. The usual root causes:
- A known provider bug at the current version.
- A computed attribute (ARN, generated name) the provider mispredicts.
default_tagsoverlapping with per-resourcetags.- A non-deterministic expression (
timestamp(),uuid()). - A Terraform-core / provider version mismatch.
- An upstream API whose response shape changed.
Capture the resource and attribute, check your versions against the provider’s issue tracker, remove unstable inputs, and pin/bump to a fixed provider version. Terraform is doing the right thing by refusing to apply an unreviewed value.
Download the Free 500-Prompt DevOps AI Toolkit
500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.
- 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
- Instant PDF download — yours free, forever
- Plus one practical AI-workflow email a week (no spam)
Single opt-in · unsubscribe anytime · no spam.