| Tested on | Ubuntu 26.04 LTS (Resolute Raccoon) |
|---|---|
| Package | terraform 1.15.8-1hashicorp/local 2.9.0 |
| Applies to | Any host with Terraform installed |
| Lab environment | Single Ubuntu VM with Terraform — Terraform lab environment on Ubuntu |
| Privilege | Normal user; sudo only if Terraform is not installed yet |
| Scope | Troubleshooting Terraform Provider configuration not present — state association with provider aliases, safe reproduce and recovery with hashicorp/local, module configuration_aliases and providers mapping, related missing-provider errors, module removal versus provider removal, refactoring guardrails, and when terraform state rm is appropriate. Does not cover cloud credentials, manual tfstate JSON editing, or provider plugin install failures. |
| Related guides | Terraform providers Terraform module inputs and outputs terraform state commands Terraform moved and removed blocks Terraform troubleshooting |
Provider configuration not present means Terraform state still binds a managed object to a provider configuration you deleted from HCL. The error names the exact provider address state expects:
provider["registry.terraform.io/hashicorp/local"].secondaryTerraform cannot refresh, update, or destroy that object without the configuration that created it. Deleting terraform.tfstate or editing state JSON by hand is not the recovery path this guide teaches.
Each scenario uses its own directory under ~/terraform-labs/terraform-provider-configuration-not-present/. Examples use hashicorp/local only — no cloud credentials required.
Why Terraform needs the original provider configuration
Every managed resource in state records which provider configuration managed it. That address includes the provider type and any alias:
provider["registry.terraform.io/hashicorp/local"] # default
provider["registry.terraform.io/hashicorp/local"].secondary # alias = "secondary"When you run terraform plan or terraform destroy, Terraform must instantiate the same configuration to talk to the API plugin that owns the object. Removing the provider block (or alias) while state still references it leaves Terraform with no configuration for that address.
This is different from a plugin that is not installed — that failure happens at terraform init. Here the plugin is present; the named configuration is missing.
Reproduce Provider configuration not present safely
Use a secondary alias and a local_file that selects it explicitly. Apply once, then delete only the aliased provider block while the resource block stays.
mkdir -p ~/terraform-labs/terraform-provider-configuration-not-present/errors/alias-removed
cd ~/terraform-labs/terraform-provider-configuration-not-present/errors/alias-removedWrite the working configuration with both provider blocks:
cat > main.tf <<'EOF'
terraform {
required_providers {
local = {
source = "hashicorp/local"
version = "~> 2.5"
}
}
}
provider "local" {}
provider "local" {
alias = "secondary"
}
resource "local_file" "z" {
provider = local.secondary
content = "alias demo"
filename = "${path.module}/z.txt"
}
EOFInitialize and create the file through the secondary alias:
terraform init -input=falseTerraform has been successfully initialized!Apply so state records the secondary provider address:
terraform apply -auto-approve -no-colorlocal_file.z: Creating...
local_file.z: Creation complete after 0s [id=dec73a40e4065d5f612e8c7ee8a2b3ad5ef7f085]
Apply complete! Resources: 1 added, 0 changed, 0 destroyed.Delete only the provider "local" { alias = "secondary" } block from main.tf. Leave the resource "local_file" "z" block and its provider = local.secondary line untouched.
Confirm state still lists the resource:
terraform state listlocal_file.zPlan now fails because the secondary configuration is gone:
terraform plan -no-colorError: Provider configuration not present
To work with local_file.z its original provider configuration at
provider["registry.terraform.io/hashicorp/local"].secondary is required, but
it has been removed. This occurs when a provider configuration is removed
while objects created by that provider still exist in the state. Re-add the
provider configuration to destroy local_file.z, after which you can remove
the provider configuration again.The message tells you the recovery order: restore the configuration, finish operations on local_file.z, then remove the alias.
Fix provider configuration removed too early
Do not skip straight to terraform state rm. Restore the provider block Terraform expects, complete lifecycle work on the affected resources, then remove the configuration.
Stay in the same directory where you reproduced the failure. State still binds local_file.z to provider["registry.terraform.io/hashicorp/local"].secondary — recreating only main.tf in a new directory would not reproduce this recovery:
cd ~/terraform-labs/terraform-provider-configuration-not-present/errors/alias-removedRestore the aliased provider block in main.tf:
cat > main.tf <<'EOF'
terraform {
required_providers {
local = {
source = "hashicorp/local"
version = "~> 2.5"
}
}
}
provider "local" {}
provider "local" {
alias = "secondary"
}
resource "local_file" "z" {
provider = local.secondary
content = "alias demo"
filename = "${path.module}/z.txt"
}
EOFPlan should show no drift:
terraform plan -no-colorNo changes. Your infrastructure matches the configuration.Destroy the file while the alias exists:
terraform destroy -auto-approve -no-colorlocal_file.z: Destroying... [id=dec73a40e4065d5f612e8c7ee8a2b3ad5ef7f085]
local_file.z: Destruction complete after 0s
Destroy complete! Resources: 1 destroyed.Remove the resource block and unused secondary alias now that state is empty:
cat > main.tf <<'EOF'
terraform {
required_providers {
local = {
source = "hashicorp/local"
version = "~> 2.5"
}
}
}
provider "local" {}
EOFValidate and confirm an empty plan:
terraform validate -no-color && terraform plan -no-colorSuccess! The configuration is valid.
No changes. Your infrastructure matches the configuration.The safe sequence:
- Restore the required
providerconfiguration (matching alias name) - Run
terraform initif provider requirements changed terraform destroyor migrate/refactor the resource (moved blocks when renaming addresses)- Remove resource or module declarations that used the alias
- Remove the provider configuration from HCL once state is clean
Fix provider aliases with modules
Child modules that use aliased provider names inside the module must declare configuration_aliases and receive configurations from the parent through providers.
mkdir -p ~/terraform-labs/terraform-provider-configuration-not-present/errors/module-provider-removed/modules/app
cd ~/terraform-labs/terraform-provider-configuration-not-present/errors/module-provider-removedChild module expects local.secondary internally:
cat > modules/app/main.tf <<'EOF'
terraform {
required_providers {
local = {
source = "hashicorp/local"
configuration_aliases = [local.secondary]
}
}
}
resource "local_file" "x" {
provider = local.secondary
content = "module file"
filename = "${path.module}/module-x.txt"
}
EOFRoot module defines the alias and passes it into the child:
cat > main.tf <<'EOF'
terraform {
required_providers {
local = {
source = "hashicorp/local"
version = "~> 2.5"
}
}
}
provider "local" {}
provider "local" {
alias = "secondary"
}
module "app" {
source = "./modules/app"
providers = {
local.secondary = local.secondary
}
}
EOFInitialize modules and apply:
terraform init -input=falseInitializing modules...
- app in modules/app
Terraform has been successfully initialized!Create the module-managed file through the mapped alias:
terraform apply -auto-approve -no-colormodule.app.local_file.x: Creating...
module.app.local_file.x: Creation complete after 0s [id=53f04d80caae85190f89cd707b12c9f88d4e6777]
Apply complete! Resources: 1 added, 0 changed, 0 destroyed.Remove the providers = { ... } block from the module "app" call while leaving the child module source in place. Plan fails before refresh:
terraform plan -no-colorError: Missing required provider configuration
on main.tf line 16:
16: module "app" {
The child module requires an additional configuration for provider
hashicorp/local, with the local name "local.secondary".
Refer to the module's documentation to understand the intended purpose of
this additional provider configuration, and then add an entry for
local.secondary in the "providers" meta-argument in the module block to
choose which provider configuration the module should use for that purpose.If you instead delete the root provider "local" { alias = "secondary" } block but keep the providers map, Terraform reports missing provider provider["registry.terraform.io/hashicorp/local"].secondary — configuration still references an alias that no longer exists.
Stay in errors/module-provider-removed/ and restore the providers map in the module block:
cat > main.tf <<'EOF'
terraform {
required_providers {
local = {
source = "hashicorp/local"
version = "~> 2.5"
}
}
}
provider "local" {}
provider "local" {
alias = "secondary"
}
module "app" {
source = "./modules/app"
providers = {
local.secondary = local.secondary
}
}
EOFPlan with no changes, then destroy:
terraform plan -no-colorNo changes. Your infrastructure matches the configuration.terraform destroy -auto-approve -no-colorDestroy complete! Resources: 1 destroyed.Remove the module block and unused secondary alias now that state is empty:
cat > main.tf <<'EOF'
terraform {
required_providers {
local = {
source = "hashicorp/local"
version = "~> 2.5"
}
}
}
provider "local" {}
EOFValidate and confirm an empty plan:
terraform validate -no-color && terraform plan -no-colorSuccess! The configuration is valid.
No changes. Your infrastructure matches the configuration.For the simpler pattern that maps a parent alias into the child's default local slot (without configuration_aliases inside the child), see the providers demo in Terraform module inputs and outputs.
Fix errors after removing a module block
Deleting an entire module block while state still holds module.app.* addresses does not always produce Provider configuration not present. On Terraform 1.15.8, plan typically proposes destroying orphaned module resources instead:
# module.app.local_file.x will be destroyed
# (because local_file.x is not in configuration)That is a configuration drift destroy — Terraform can still reach the default provider. The risky mistake is removing the provider alias while module resources in state were created through that alias, or removing provider configuration before you destroy or migrate module-managed objects.
Safe module cleanup sequence:
terraform state list— notemodule.NAME.*addresses- Remove the module block and apply the resulting destroy plan. Use targeted destroy only when you have a specific recovery reason and understand the dependency implications
- Remove
providersmappings and unusedprovideraliases only after state no longer references those objects - For refactors that should keep real infrastructure, use a
removedblock or terraform state commands deliberately — not as a panic response to provider errors
When terraform state rm is appropriate
terraform state rm removes a resource address from state without calling the provider. It does not recreate a missing provider configuration and is not the default fix for Provider configuration not present.
Use state rm when you intend Terraform to stop managing real infrastructure that should survive — handoff to another tool, objects created outside Terraform, or pairing with a removed block. Use terraform destroy when you want the provider to delete managed objects.
The terraform state commands lesson covers state rm versus destroy in depth. The Terraform moved and removed blocks lesson shows declarative removed { lifecycle { destroy = false } } for stopping management without destroy.
Do not treat state rm as a universal recovery lever when you still owe a destroy through the original provider alias.
Avoid this error during refactoring
- Keep provider configurations at the root module unless a wrapper explicitly documents otherwise
- Pass aliased configurations into children with
providers = { ... }when the child declaresconfiguration_aliases - Destroy or migrate resources before deleting the provider block that state references
- Run
terraform state listandterraform providersbefore removing aliases from a long-lived stack - Prefer
movedandremovedblocks in version control over one-off state surgery
Diagnostic checklist
| Symptom | Likely cause | Fix |
|---|---|---|
| Provider configuration not present | State references removed provider alias | Re-add alias block; destroy or migrate; then remove alias |
| Missing required provider configuration | Module providers map removed |
Restore providers entry for each configuration_aliases name |
| missing provider …local.secondary | Resource or map references undefined alias | Re-add provider block with alias = "secondary" |
| Plan destroys module resources after module block deleted | Orphaned state addresses | Apply destroy or restore module block; not a provider-config error |
| Plugin not installed | terraform init not run |
Run terraform init — different failure class |
Verify the fix
After you complete the cleanup steps above — destroy dependent objects, then remove obsolete resource or module declarations and unused provider aliases — validate and plan in each directory:
cd ~/terraform-labs/terraform-provider-configuration-not-present/errors/alias-removed
terraform validate -no-color && terraform plan -no-colorSuccess! The configuration is valid.
No changes. Your infrastructure matches the configuration.Repeat in errors/module-provider-removed/ after its cleanup. If you stopped mid-lab, destroy any remaining resources before deleting the lab tree:
cd ~/terraform-labs/terraform-provider-configuration-not-present/errors/alias-removed && terraform destroy -auto-approve -input=false 2>/dev/null || true
cd ~/terraform-labs/terraform-provider-configuration-not-present/errors/module-provider-removed && terraform destroy -auto-approve -input=false 2>/dev/null || trueReferences
- Provider configuration — HashiCorp Developer
- Provider aliases — HashiCorp Developer
- Module providers meta-argument — HashiCorp Developer
- configuration_aliases — HashiCorp Developer
Summary
Provider configuration not present appears when state still ties a resource to a provider address you removed from configuration — commonly an alias such as local.secondary on a local_file that still declares provider = local.secondary. Terraform needs that block back long enough to refresh or destroy the object.
Module stacks add configuration_aliases in the child and a providers map in the parent. Removing either side while resources exist produces missing-provider errors that are cousins of the same mistake: configuration and state no longer agree on which provider instance owns the object.
Recover by restoring configuration, running destroy or a declarative refactor, then deleting provider blocks only when terraform state list shows no dependents. Reserve terraform state rm for cases where infrastructure should outlive Terraform management — not as the first response to a removed alias.
For alias basics and plugin installation, continue with Terraform providers. For imperative state edits, see terraform state commands.

