Fix Terraform "Provider Configuration Not Present" Error

Tested on Ubuntu 26.04 LTS (Resolute Raccoon)
Package terraform 1.15.8-1
hashicorp/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:

text
provider["registry.terraform.io/hashicorp/local"].secondary

Terraform 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.

NOTE
Run terraform init in each new directory before terraform apply or terraform plan. Lab files are disposable; destroy resources when you finish.

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:

text
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.

bash
mkdir -p ~/terraform-labs/terraform-provider-configuration-not-present/errors/alias-removed
cd ~/terraform-labs/terraform-provider-configuration-not-present/errors/alias-removed

Write the working configuration with both provider blocks:

bash
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"
}
EOF

Initialize and create the file through the secondary alias:

bash
terraform init -input=false
output
Terraform has been successfully initialized!

Apply so state records the secondary provider address:

bash
terraform apply -auto-approve -no-color
output
local_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:

bash
terraform state list
output
local_file.z

Plan now fails because the secondary configuration is gone:

bash
terraform plan -no-color
output
Error: 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:

bash
cd ~/terraform-labs/terraform-provider-configuration-not-present/errors/alias-removed

Restore the aliased provider block in main.tf:

bash
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"
}
EOF

Plan should show no drift:

bash
terraform plan -no-color
output
No changes. Your infrastructure matches the configuration.

Destroy the file while the alias exists:

bash
terraform destroy -auto-approve -no-color
output
local_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:

bash
cat > main.tf <<'EOF'
terraform {
  required_providers {
    local = {
      source  = "hashicorp/local"
      version = "~> 2.5"
    }
  }
}

provider "local" {}
EOF

Validate and confirm an empty plan:

bash
terraform validate -no-color && terraform plan -no-color
output
Success! The configuration is valid.

No changes. Your infrastructure matches the configuration.

The safe sequence:

  1. Restore the required provider configuration (matching alias name)
  2. Run terraform init if provider requirements changed
  3. terraform destroy or migrate/refactor the resource (moved blocks when renaming addresses)
  4. Remove resource or module declarations that used the alias
  5. 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.

bash
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-removed

Child module expects local.secondary internally:

bash
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"
}
EOF

Root module defines the alias and passes it into the child:

bash
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
  }
}
EOF

Initialize modules and apply:

bash
terraform init -input=false
output
Initializing modules...
- app in modules/app
Terraform has been successfully initialized!

Create the module-managed file through the mapped alias:

bash
terraform apply -auto-approve -no-color
output
module.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:

bash
terraform plan -no-color
output
Error: 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:

bash
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
  }
}
EOF

Plan with no changes, then destroy:

bash
terraform plan -no-color
output
No changes. Your infrastructure matches the configuration.
bash
terraform destroy -auto-approve -no-color
output
Destroy complete! Resources: 1 destroyed.

Remove the module block and unused secondary alias now that state is empty:

bash
cat > main.tf <<'EOF'
terraform {
  required_providers {
    local = {
      source  = "hashicorp/local"
      version = "~> 2.5"
    }
  }
}

provider "local" {}
EOF

Validate and confirm an empty plan:

bash
terraform validate -no-color && terraform plan -no-color
output
Success! 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:

text
# 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:

  1. terraform state list — note module.NAME.* addresses
  2. 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
  3. Remove providers mappings and unused provider aliases only after state no longer references those objects
  4. For refactors that should keep real infrastructure, use a removed block 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 declares configuration_aliases
  • Destroy or migrate resources before deleting the provider block that state references
  • Run terraform state list and terraform providers before removing aliases from a long-lived stack
  • Prefer moved and removed blocks 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:

bash
cd ~/terraform-labs/terraform-provider-configuration-not-present/errors/alias-removed
terraform validate -no-color && terraform plan -no-color
output
Success! 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:

bash
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 || true

References


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.


Frequently Asked Questions

1. What does Provider configuration not present mean in Terraform?

State still records resources managed through a provider configuration address such as provider["hashicorp/local"].secondary, but that provider block or alias no longer exists in your configuration. Terraform needs the original configuration to refresh, update, or destroy those objects.

2. How do I fix Provider configuration not present?

Re-add the missing provider configuration block with the same alias name, run terraform init if needed, destroy or migrate the affected resources, then remove the provider configuration only after nothing in state references that address.

3. Is terraform state rm the right fix for this error?

state rm forgets a resource in state without calling the provider. It does not fix a missing provider configuration when you still need to destroy managed objects through that provider. Use state rm only when you deliberately want Terraform to stop managing real infrastructure that should survive.

4. Why does removing a module providers map cause errors?

A child module that declares configuration_aliases expects the parent to pass matching provider configurations through the providers meta-argument. Removing the map leaves the module without the local.secondary configuration it requires.

5. What is the difference between Provider configuration not present and missing provider?

Provider configuration not present means state references a provider address that used to exist but was removed from configuration. Missing provider usually means configuration still references a provider alias that is not defined, such as local.secondary in a resource block when the provider block was deleted.
Deepak Prasad

R&D Engineer

Founder of GoLinuxCloud with more than 15 years of expertise in Linux, Python, Go, Laravel, DevOps, Kubernetes, Git, Shell scripting, OpenShift, AWS, Networking, and Security. With extensive experience, he excels across development, DevOps, networking, and security, delivering robust and efficient solutions for diverse projects.

  • Go (programming language)
  • Python (programming language)
  • DevOps
  • Computer Security
  • Cloud Computing
  • Kubernetes
  • Linux
  • Ansible (software)