Fix Terraform Error: Provider configuration not present safely
Terraform Error: Provider configuration not present means state still associates one or more managed resource instances with a provider configuration address that the current root module can no longer supply. The missing object may be a deleted child-module provider block, a removed alias, an absent module call, or a changed provider source. Repair the execution context before planning any infrastructure change.
Identify the exact state, resource addresses, provider source, module path, and alias named by the error; reconstruct the smallest matching provider configuration; then either migrate retained resources to root-owned provider configuration or destroy intentionally retired resources through a reviewed saved plan, without recreating objects or editing state by hand.
- Terraform CLI 1.7.x, 1.8.x, 1.9.x, 1.10.x and current supported releases
- Providers HashiCorp and partner providers using root or aliased configurations
- Execution local CLI, CI runners, HCP Terraform and Terraform Enterprise workspaces
- Exact execution context Work from the same root module, backend initialization, workspace, variable set, provider credentials, and configuration revision that produced the failure. A similarly named directory or workspace can point at unrelated state.
terraform version && terraform workspace show - Read-only state access The responder must be able to run terraform providers, terraform state list, and a protected terraform state pull without widening provider permissions or exposing state values.
Confirm the state backend and evidence storage are approved for this environment. - Configuration history Keep access to Git history, module release history, previous pipeline artifacts, and the last successful run so the missing module path, provider source, alias, region, account, and subscription can be reconstructed.
git log --oneline --decorate -n 20 - Change coordination Freeze applies, imports, destroys, and state commands for this state. One incident owner should approve the recovery branch and every state-changing plan.
Confirm the CI concurrency queue and remote-run workspace have no active writer. - Recovery access Prepare an encrypted evidence location outside source control. Terraform state can include credentials and sensitive resource attributes even when command output appears harmless.
Verify the incident directory is excluded from Git and restricted to the recovery team.
OneLiners never runs these steps or stores secrets. Review placeholders, versions, current state, and change-control requirements before using a command.
Full guide
What you will build
- A reproducible evidence bundle that ties Error: Provider configuration not present to one root, backend, workspace, resource address, provider source, module path, and alias.
- A complete inventory of retained, retired, and unknown objects before provider configuration is restored.
- A minimal recovery configuration that restores only the identity Terraform requires and never resurrects old secrets.
- A safe keep branch that moves provider ownership to root configuration through configuration_aliases and providers maps.
- A separate retire branch that destroys only owner-approved objects through an immutable saved plan.
- A final proof covering provider graph, state lineage and serial, resource inventory, normal locking, and plan convergence.
- Explain why provider installation is different from provider configuration and state association.
- Read the orphan resource address and original provider configuration address from the literal error.
- Prove the correct backend, workspace, root module, Git revision, Terraform version, and provider lock file.
- Compare providers required by configuration with providers required by state.
- Extract provider-binding metadata without disclosing resource values from state.
- Reconstruct a removed alias or child-module provider through current approved authentication.
- Keep existing objects managed without recreation by passing root provider configurations explicitly.
- Retire objects only while their original provider configuration remains available.
- Recognize when state replace-provider is relevant to provider-source migration and when it is the wrong tool for aliases.
- Verify final state identity and prevent the error through module design and decommission ordering.
Architecture
How the parts fit together
Terraform stores two related but distinct ideas: the provider source that supplies resource types and a provider configuration instance that supplies settings and credentials. State remembers which configuration last managed each resource. A root module constructs provider configurations and passes them to children. Safe recovery restores that graph long enough to migrate or finish lifecycle operations.
- A root configuration initializes one backend and selects one workspace.
- Terraform loads required provider sources and constructs default or aliased provider configurations in the root.
- Module providers maps pass those configurations to child modules that declare compatible requirements and aliases.
- When Terraform manages a resource, state records the resource address and provider configuration association.
- A refactor removes a module call, nested provider block, alias, or provider source while associated resources remain in state.
- Terraform cannot refresh, plan, or destroy the orphan because the configuration needed for provider communication is absent.
- Evidence collection identifies the exact state, resource set, provider source, module path, alias, and last successful configuration.
- The responder reintroduces the smallest matching provider configuration with current approved authentication.
- Retained resources move to root-owned mappings; retired resources complete destruction while the original configuration exists.
- Final checks prove the old association is gone only after no resource depends on it and the normal plan is coherent.
Assumptions
- The failure comes from a traditional Terraform configuration and state, not a Terraform Stack component configuration.
- The responder can access the authoritative backend and workspace in read-only mode before requesting changes.
- Git or module release history preserves enough non-secret structure to identify the removed provider configuration.
- Provider credentials are supplied through current approved workload identity, environment, or secret management.
- All writers for the affected state can be frozen during recovery.
- The current state lineage is known and state snapshots are treated as secret-bearing data.
- Resource owners can classify every affected object as keep, retire, or unknown.
- The provider source and major version remain supported for the recovery window.
- No one will use -lock=false, edit state JSON, or delete backend coordination records.
- Windows operators translate POSIX evidence commands to PowerShell while preserving the same data minimization.
Key concepts
- Provider source
- The globally unique plugin address declared in required_providers, such as hashicorp/aws. It controls installation and schema, not environment-specific settings.
- Provider configuration
- A configured instance of a provider with settings and authentication context. Terraform resources depend on one such instance for refresh, update, and destroy.
- Provider alias
- A local name for an alternate provider configuration. Default and aliased instances of the same source are not interchangeable identities.
- Configuration address
- The provider identity within the root and module graph, including module path and alias, retained in state for managed resources.
- Orphan resource
- A state-tracked resource whose configuration or provider configuration needed for lifecycle operations is no longer available.
- Root provider ownership
- The recommended pattern where environment-specific provider configurations live in the root and are passed to reusable child modules.
- configuration_aliases
- A child-module declaration listing alternate provider names the caller may supply.
- providers meta-argument
- A map on a module call that connects provider names expected by the child to concrete configurations owned by the parent.
- State lineage
- A stable identity for one state history; a mismatch means the responder may be inspecting or overwriting another state.
- State serial
- The state generation counter. Unexplained movement during recovery suggests another writer or state operation.
- state replace-provider
- A state command that changes provider source addresses. It does not recreate a missing alias or module-scoped configuration and is not the default fix for this error.
- Saved plan
- An immutable Terraform plan artifact reviewed before apply; it can contain secrets and becomes stale if inputs or state change.
Fill these once. Every matching command and configuration block updates immediately; values stay in this page only.
Security and production boundaries
- Terraform state and saved plans can contain secrets even when values are marked sensitive. Keep them encrypted, access controlled, and out of Git.
- Never restore credentials from source history. Use current workload identity or an approved secret manager and rotate anything exposed.
- Provider configuration determines cloud account, project, subscription, region, endpoint, and role. Valid authentication to the wrong target is a critical stop condition.
- Do not use terraform state rm to silence the error; it abandons management while leaving the remote object.
- Do not import the existing object into a second address before resolving the original ownership; duplicate management can cause destructive plans.
- Do not edit state JSON or run terraform state push -force as routine repair.
- Do not use terraform state replace-provider for a missing alias or module path. It changes provider source association and requires a separate review.
- Do not remove the restored provider configuration until every associated resource is migrated or destroyed.
- Keep state locking enabled and serialize recovery through the same CI or remote workspace.
- Review provider and module version constraints without upgrading dependencies during the incident.
- Require explicit approval for every saved plan that changes state or infrastructure.
- Sanitize resource addresses and provider metadata before public discussion.
Stop before continuing if
- The root module, backend, organization, state key, workspace, or state lineage is uncertain.
- Another local, CI, scheduler, or remote run can write the same state.
- The provider address in the error is incomplete, changing, or not present in the protected state metadata.
- The recovered provider points to an unexpected account, project, subscription, tenant, region, or endpoint.
- Any affected resource lacks a named owner or keep/retire decision.
- The proposed repair uses state rm, manual state editing, state push -force, duplicate import, or -lock=false.
- A source-address migration is being confused with an alias or module-scope problem.
- Terraform or provider versions changed during recovery without a dedicated compatibility review.
- A plan includes unexplained creation, destruction, replacement, import, or unrelated drift.
- State serial changes while evidence is collected and no approved run explains it.
- A saved plan or state snapshot cannot be protected as sensitive evidence.
- A stateful service lacks a tested backup before an approved destroy.
command
Capture the complete Error: Provider configuration not present diagnostic
Run a refresh-disabled plan only to reproduce the configuration-to-state binding error. Preserve the complete message, especially the orphan resource address and the original provider configuration address. Do not shorten it to the headline because the module path and provider address decide the repair.
Why this step matters
The first diagnostic is the most reliable map from the affected state object to the missing provider configuration. Refresh is disabled so provider-side reads do not obscure a structural failure, while locking remains enabled to protect state.
What to understand
Copy the full resource address, including every module instance key, count index, and for_each key. A repair for module.database is not automatically valid for module.database["prod"].
Copy the complete provider address, including registry source, module path, and alias suffix. Default and aliased configurations are different identities.
Record the root directory, Git commit, workspace, backend, run ID, operator, and UTC timestamp beside the error.
If the command waits for a lock, resolve the lock as a separate incident. Do not add -lock=false.
System changes
- No remote infrastructure or state is intentionally changed; the command may obtain and release a normal state lock.
Syntax explained
-refresh=false- Avoid provider refresh while reproducing a configuration-graph error.
-input=false- Fail instead of waiting for hidden interactive values in automation.
-lock-timeout=2m- Waits briefly for legitimate contention while retaining locking.
-no-color- Produces stable evidence for review.
terraform plan -refresh=false -input=false -lock-timeout=2m -no-colorError: Provider configuration not present To work with module.database.aws_db_instance.primary (orphan) its original provider configuration at module.database.provider["registry.terraform.io/hashicorp/aws"].legacy 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.
Checkpoint: The exact missing identity is recorded
terraform plan -refresh=false -input=false -lock-timeout=2m -no-colorContinue whenThe output names at least one orphan resource and its original provider configuration address.
Stop whenThe message instead reports backend access, state lock, provider authentication, or configuration syntax failure.
If this step fails
The plan reports Error acquiring the state lock before the provider error
Likely causeAnother writer owns the state or backend locking is unhealthy.
Inspect the lock owner and active CI or remote runs.Use the dedicated state-lock recovery Guide.
ResolutionStop this procedure until normal locking works.
The plan asks for variables or credentials
Likely causeThe shell does not match the failed run's execution context.
Compare variable files, environment variables, workload identity, and remote workspace settings.Do not paste secrets into the command line or ticket.
ResolutionRestore the intended non-interactive context, then reproduce again.
Security notes
- The error text can expose account names, paths, resource addresses, and usernames. Sanitize copies before sharing.
- Never disable locking merely to collect the message.
Alternatives
- If production reproduction is not authorized, use the preserved failed-run output and compare it with a non-production copy of the same module graph.
Stop conditions
- The root module, backend, or workspace is uncertain.
- A writer is active or the lock changes during collection.
command
Prove the Terraform version, workspace, and initialized root
Confirm that the shell is in the intended root module and that the selected workspace matches the state named by the incident. Inspect backend configuration files without printing credentials. Compare this context with the last successful pipeline before touching configuration.
Why this step matters
Provider configuration addresses are evaluated inside one root configuration and one state. The same HCL checked out elsewhere can be initialized to another backend, and the same root can select another workspace.
What to understand
Compare Terraform and provider versions with the failed run rather than upgrading during recovery.
Review the backend block and .terraform/terraform.tfstate metadata locally, but do not copy cached credentials or full backend configuration into evidence.
For HCP Terraform or Terraform Enterprise, confirm organization, project, workspace, execution mode, variable sets, and configuration version.
For CI, confirm the repository path, working-directory setting, checkout SHA, and downloaded module versions.
System changes
- No intended change. Git and Terraform context are read; provider plugins are not upgraded.
Syntax explained
terraform workspace show- Prints the selected CLI workspace that chooses a state instance.
git rev-parse --show-toplevel- Identifies the repository root used by the current shell.
git rev-parse HEAD- Records the exact configuration revision.
terraform version && terraform workspace show && git rev-parse --show-toplevel && git rev-parse HEADTerraform v1.10.5 on linux_amd64 prod /srv/iac/platform-live 8d1f7d4a3b0fcb95b35f0c89f7f5747cc370f56b
Checkpoint: Execution identity matches the failed run
terraform version && terraform workspace show && git rev-parse HEADContinue whenVersion, workspace, and revision are known and match the intended incident context.
Stop whenThe workspace, backend, repository, or revision differs from the failing execution.
If this step fails
terraform workspace show returns default unexpectedly
Likely causeThe directory was initialized for another backend or workspace selection was lost.
Inspect the failed run settings and backend initialization record.List workspaces only after confirming the backend.
ResolutionSelect the intended workspace through the normal run configuration; never guess from its name.
The local provider version differs from CI
Likely causeThe dependency lock file or initialization inputs are inconsistent.
Compare .terraform.lock.hcl and terraform version.Do not run terraform init -upgrade during recovery.
ResolutionRestore the reviewed dependency lock and normal initialization process.
Security notes
- Do not print environment variables, backend credentials, cloud tokens, or remote variable values.
- Treat .terraform metadata as potentially sensitive.
Alternatives
- Perform the recovery in the normal CI or remote workspace if local execution cannot faithfully reproduce its identity.
Stop conditions
- Any identifier points to a different environment.
- The dependency lock file changed without review.
command
Compare providers required by configuration and by state
Use terraform providers to display the provider requirements Terraform derives from the current module tree and the providers still referenced by state. Look for a provider that exists only under state, a missing alias, or a module path that disappeared from configuration.
Why this step matters
This comparison separates installation requirements from configuration instances and state ownership. A provider binary can be installed correctly while the specific configuration address required by a resource is absent.
What to understand
A provider source such as registry.terraform.io/hashicorp/aws identifies the plugin, not the alias configuration or its region and credentials.
An alias suffix such as .legacy identifies a distinct configuration instance. Adding an unrelated default provider block does not necessarily satisfy it.
A module path in the state section shows where Terraform last associated the resource with a provider configuration.
Record every state-only provider address; one error may hide additional orphaned instances until the first is repaired.
System changes
- No state, configuration, or provider-side object is changed.
Syntax explained
terraform providers- Shows provider requirements discovered from configuration and provider associations discovered from state.
terraform providersProviders required by configuration:
.
├── provider[registry.terraform.io/hashicorp/aws] 5.92.0
└── module.database
└── provider[registry.terraform.io/hashicorp/random]
Providers required by state:
provider[registry.terraform.io/hashicorp/aws]
module.database.provider[registry.terraform.io/hashicorp/aws].legacyCheckpoint: The missing provider address is classified
terraform providersContinue whenThe provider source, module path, and alias needed by each affected state object are recorded.
Stop whenThe command cannot read the intended state or returns a different provider graph than the failed run.
If this step fails
The provider appears under both headings but the error remains
Likely causeThe source matches but a particular alias or module-scoped configuration is absent.
Compare the full error address, not only the provider source.Inspect module providers maps and configuration_aliases.
ResolutionReconstruct the exact alias mapping before planning repairs.
A provider source changed from hashicorp to a private registry
Likely causeThis may be a source-address migration, not an alias removal.
Compare required_providers history and the dependency lock.Read the state replace-provider documentation.
ResolutionKeep source migration separate; do not use replace-provider for alias-only problems.
Security notes
- Provider addresses are safe metadata, but module names can reveal internal architecture. Sanitize public evidence.
Alternatives
- If terraform providers cannot run, obtain the same provider graph from the failed-run artifact and protected state metadata.
Stop conditions
- The configuration and state headings refer to different roots or workspaces.
- Several unexplained provider-source changes are mixed into one recovery.
command
Inventory every resource tied to the missing module or alias
List state addresses and filter only by the exact module path or resource prefix from the error. Do not remove anything. Expand count and for_each instances so the decision owner understands the real blast radius.
Why this step matters
A provider repair can unlock planning for many resources, not only the first address printed in the error. An explicit inventory prevents accidental destruction or adoption decisions based on one visible object.
What to understand
Preserve complete addresses including quoted keys; shell filtering is for review only and is never passed into a state mutation.
Map each address to its owner, environment, criticality, replacement impact, and intended lifecycle.
Compare the list with the last successful plan or state inventory to identify unexpected additions.
If the module block was removed, inspect its previous output dependencies before restoring or retiring it.
System changes
- No state entries are changed. The command reads the state address index.
Syntax explained
terraform state list- Lists resource instances Terraform currently tracks.
grep '^module\.database'- Narrows display to the exact reviewed module prefix.
sort- Creates a stable inventory for comparison.
terraform state list | grep '^module\.database' | sortmodule.database.aws_db_instance.primary module.database.aws_db_parameter_group.primary module.database.aws_security_group.database module.database.random_password.master
Checkpoint: Blast radius is complete
terraform state list | grep '^module\.database' | sortContinue whenEvery affected address is listed and assigned an intended keep or retire decision.
Stop whenThe filter matches unrelated module instances or the list differs from the protected production inventory.
If this step fails
Only the first orphan appears in the plan error
Likely causeTerraform stopped evaluation at the first missing binding.
Use terraform state list and state metadata.Review all provider addresses before repairing.
ResolutionBuild the complete inventory before changing HCL.
A resource address is absent from configuration but still exists in state
Likely causeThe module or resource block was removed before lifecycle completion.
Review Git history and cloud inventory read-only.Decide whether the object must remain managed or be intentionally destroyed.
ResolutionDo not import, recreate, or remove state until ownership is resolved.
Security notes
- Resource names can reveal production topology. Keep the inventory in restricted incident evidence.
Alternatives
- Use terraform state list with an exact address argument when grep is unavailable on Windows.
Stop conditions
- Any listed resource has unknown ownership or replacement consequences.
- The inventory includes a shared or regulated resource without its owner.
command
Preserve protected state and extract provider references
Pull the current state only into an encrypted, access-controlled incident directory outside source control. Compute a checksum, then create a sanitized provider-address report that excludes resource values. Never attach the raw state to a public issue.
Why this step matters
State is the authoritative binding record and may contain secrets. A protected snapshot and checksum make recovery auditable and support containment if a later plan or apply updates provider associations unexpectedly.
What to understand
The raw snapshot must stay encrypted, access controlled, and outside the repository. Delete it according to incident-retention policy after closure.
The provider report includes only module, resource type, resource name, and provider address; it deliberately omits instance attributes.
Record lineage, serial, and Terraform version in a separate sanitized note so later state changes can be explained.
Do not use terraform state push during this procedure. A snapshot is evidence, not an automatic rollback artifact.
System changes
- Creates a restricted local incident directory and evidence files; reads but does not write the backend state.
Syntax explained
umask 077- Restricts new evidence files to the current user on POSIX systems.
terraform state pull- Reads the latest state snapshot from the selected backend.
sha256sum- Records an integrity checksum without exposing state contents.
jq -r- Extracts only provider-binding metadata into a reviewable report.
Values stay on this page and are never sent or saved.
umask 077 && mkdir -p '{{evidenceDir}}' && terraform state pull > '{{evidenceDir}}/state-before.json' && sha256sum '{{evidenceDir}}/state-before.json' > '{{evidenceDir}}/state-before.sha256' && jq -r '.resources[] | [.module // "root", .type, .name, .provider] | @tsv' '{{evidenceDir}}/state-before.json' > '{{evidenceDir}}/provider-bindings.tsv'$ cat /secure/incidents/INC-1902/provider-config/state-before.sha256 2f0f1e9ab753fc0b149f3bf93497ac56f6d7cbfab2826596cb6ff04cc22bb762 /secure/incidents/INC-1902/provider-config/state-before.json $ grep 'module.database' /secure/incidents/INC-1902/provider-config/provider-bindings.tsv module.database aws_db_instance primary provider["registry.terraform.io/hashicorp/aws"].legacy
Checkpoint: State evidence is protected and attributable
sha256sum -c '{{evidenceDir}}/state-before.sha256'Continue whenThe checksum passes and the provider report contains the missing configuration address.
Stop whenThe evidence directory is not approved, the lineage is unexpected, or state cannot be read consistently.
If this step fails
State pull includes secrets in clear text
Likely causeTerraform state records provider-returned attributes and sensitive values.
Inspect permissions without opening values.Confirm encryption and incident access controls.
ResolutionRestrict the snapshot immediately; never paste it into chat, Lific, or source control.
The serial changes between two reads
Likely causeAnother writer may still be active.
Freeze all writers and compare run history.Preserve both checksums and timestamps.
ResolutionStop routine recovery and investigate concurrent state activity.
Security notes
- Raw state must never be committed, uploaded to a public ticket, or sent to an AI service.
- Use a platform-appropriate encrypted folder on Windows rather than assuming umask semantics.
Alternatives
- If policy forbids local state copies, use an approved backend version snapshot and extract metadata within the controlled environment.
Stop conditions
- State lineage is not the expected environment.
- Serial changes without a known successful operation.
command
Reconstruct the removed provider configuration from version history
Search Git and module release history for the exact module path, provider alias, providers map, and required_providers source. Compare the last successful configuration with the commit that introduced the failure. Recover structure, not old secrets.
Why this step matters
Terraform needs a provider configuration with the identity recorded in state. The best source is the reviewed configuration that last operated those resources successfully, combined with current credential and policy controls.
What to understand
Recover provider source, local name, alias, module path, region or endpoint, assume-role settings, and how credentials were supplied.
Do not recover expired access keys, tokens, passwords, certificates, or secret tfvars from history.
Compare module version changes and providers mappings at every caller level when modules are nested.
Confirm whether the provider block disappeared intentionally during refactoring or accidentally during a partial deployment.
System changes
- No repository change is made; history and previous file versions are read.
Syntax explained
git log -S- Finds commits that added or removed the exact configuration text.
--all- Searches reachable branches and references, not only the current branch.
-p- Shows the reviewed configuration diff that changed provider ownership.
git log --all --oneline -S 'alias = "legacy"' -- '*.tf' && git log --all -p -- modules/database '*.tf'31f4c02 Move database provider to root module
8ce2a71 Add legacy database region
commit 31f4c02d7a91f06d9a...
- provider "aws" {
- alias = "legacy"
- region = "us-east-1"
- }Checkpoint: A minimal restoration specification exists
git log --all -S 'alias = "legacy"' --oneline -- '*.tf'Continue whenThe commit and exact prior provider configuration structure are identified without copying secrets.
Stop whenHistory does not prove which account, region, alias, or module path created the resources.
If this step fails
The alias name exists in several modules
Likely causeAlias names are local to configuration scopes and are not globally unique.
Match the full provider address from the error.Trace each nested module caller.
ResolutionRestore only the configuration at the exact module path.
The provider block contained inline credentials
Likely causeLegacy configuration violated secret-management policy.
Recover only non-secret settings.Use current workload identity or approved secret injection.
ResolutionDo not resurrect credentials from Git history; rotate exposed secrets separately.
Security notes
- Treat secret material found in Git as compromised and follow credential-rotation policy.
- Do not check out an old branch and apply it wholesale; isolate the minimal provider repair.
Alternatives
- The original account or region cannot be proven.
- The only available recovery depends on expired or exposed credentials.
config
Reintroduce the exact missing provider configuration before any lifecycle change
Create a minimal recovery commit that restores the module call and the provider configuration identity named by the error. Use current approved authentication. Do not re-add removed resource blocks merely to silence the error unless the intended keep or retire branch requires them.
Why this step matters
HashiCorp documents that resources remain associated with the provider configuration most recently used for them. Reintroducing the original configuration restores Terraform's ability to refresh, plan, or destroy those objects before the provider block is removed again.
What to understand
Use the exact provider source and alias from the error and state report. A differently named alias is a new configuration.
Restore the module at the same path and instance key when count or for_each was involved.
Supply authentication through the current approved identity mechanism, not inline HCL or recovered secrets.
Keep the recovery change isolated so reviewers can distinguish provider restoration from infrastructure intent.
System changes
- Adds a temporary provider configuration and, if needed, restores the module call in the recovery branch. It does not by itself change remote infrastructure or state.
Syntax explained
required_providers- Declares the global provider source and version requirement.
provider "aws"- Defines one provider configuration instance.
alias = "legacy"- Recreates the configuration name recorded by state.
module "database"- Restores the module path needed to address the orphaned resources.
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.92"
}
}
}
module "database" {
source = "./modules/database"
}
# Temporary recovery configuration at the original module scope.
# Do not place credentials in this block.
# modules/database/provider-recovery.tf
provider "aws" {
alias = "legacy"
region = "us-east-1"
}Success! The configuration is valid.
Checkpoint: Configuration validates with the original identity present
terraform fmt -check -recursive && terraform validateContinue whenFormatting and validation pass, and the next refresh-disabled plan no longer reports Error: Provider configuration not present.
Stop whenValidation selects another provider source, asks for unapproved credentials, or the error names a different missing address.
If this step fails
terraform validate says provider configuration reference is undefined
Likely causeThe child module expects an alias that is not declared or mapped.
Inspect configuration_aliases in the child required_providers block.Inspect the parent module providers map.
ResolutionAdd the exact alias declaration and mapping, then validate again.
The error moves to another orphan resource or alias
Likely causeSeveral provider configurations were removed.
Return to terraform providers and the protected binding report.Inventory every missing address.
ResolutionRestore each configuration deliberately; do not add speculative aliases.
Security notes
- Provider settings can select a different account or region even when credentials are valid. Verify identity before any normal refresh.
- Temporary recovery HCL must still follow code review and secret-scanning rules.
Alternatives
- If the old provider configuration cannot be safely recreated, stop and engage the provider and Terraform support with sanitized state metadata.
Stop conditions
- The provider identity points to the wrong account, region, subscription, project, or endpoint.
- The fix requires embedding credentials or weakening authentication.
decision
Choose whether each affected object stays managed or is intentionally retired
After the missing configuration exists, classify every affected address as keep, retire, or unknown. Keep and retire are different workflows. The decision must come from the service owner and current provider reality, not from whether Terraform can now produce a plan.
Why this step matters
Provider restoration only re-enables Terraform. It does not decide whether an object should continue to exist. Mixing refactoring with destruction is how an apparently structural fix becomes an outage.
What to understand
For KEEP, migrate provider ownership to a root-owned configuration and prove an empty or fully explained plan.
For RETIRE, retain the original provider configuration until Terraform destroys the objects through an approved saved plan.
For UNKNOWN, stop. State removal would orphan the real object, while import or recreation could duplicate it.
Split mixed outcomes into separate reviewed plans if the blast radius or owners differ.
System changes
- Creates an incident decision record; no Terraform state or provider object is changed.
Syntax explained
KEEP- The remote object remains and Terraform must retain management through a valid provider mapping.
RETIRE- The remote object is intentionally destroyed while its original provider configuration still exists.
UNKNOWN- No action is authorized until ownership and lifecycle are established.
Decision record KEEP: module.database.aws_db_instance.primary — production database remains managed KEEP: module.database.aws_db_parameter_group.primary — required by database RETIRE: none UNKNOWN: none Owner: database-platform Approved: 2026-08-23T18:10:00Z
Checkpoint: Every address has an owner-approved lifecycle
Continue whenThere are no unknown objects and the keep and retire sets are explicit.
Stop whenAny resource is shared, regulated, irreplaceable, or lacks a named owner.
If this step fails
The owner wants to keep the object but remove it from state
Likely causeState removal abandons management and hides drift rather than repairing provider ownership.
Confirm why Terraform management is being retired.Review import and ownership boundaries separately.
ResolutionDo not use state rm as a shortcut; create a dedicated decommission or ownership-transfer plan.
The owner expects Terraform to recreate the object
Likely causeThe existing object may be stateful or externally referenced.
Inspect provider reality and replacement consequences.Compare identifiers and dependencies.
ResolutionPreserve the object and migrate provider mapping unless a separate replacement project is approved.
Security notes
- The decision record must not include secrets or raw state.
- Destruction requires normal change-control and recovery evidence.
Alternatives
- Pause after provider restoration and leave the state unchanged until owners decide.
Stop conditions
- Any object remains unknown.
- A proposed plan mixes unrelated infrastructure changes.
config
For retained resources, move provider ownership to the root module
Define provider configurations in the root module, declare any aliases expected by the child module through configuration_aliases, and pass them explicitly with the module providers map. Remove the nested provider block only in the same reviewed refactor after a refresh-disabled plan proves Terraform can resolve the new mapping.
Why this step matters
Terraform recommends provider configurations in the root module and passes them to children. Explicit aliases and providers maps make ownership visible, reusable, and compatible with module refactoring while keeping the existing remote objects.
What to understand
The child module declares requirements and aliases but does not contain credentials or provider configuration settings.
The parent providers map keys are the names expected inside the child; values are root provider configurations.
Perform this refactor against the same module instance path and provider source recorded in state.
Review the complete plan for address changes, replacements, provider-account changes, and unrelated drift before any apply.
System changes
- Moves provider configuration ownership in HCL. A later reviewed apply may update state associations even when it makes no remote infrastructure change.
Syntax explained
configuration_aliases- Declares alternate provider names the child module is allowed to receive.
providers = { ... }- Maps child provider names to concrete root provider configurations.
aws.legacy- Refers to the explicit root alias; it is not a quoted string.
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.92"
}
}
}
provider "aws" {
alias = "legacy"
region = "us-east-1"
}
module "database" {
source = "./modules/database"
providers = {
aws.legacy = aws.legacy
}
}
# modules/database/terraform.tf
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
configuration_aliases = [aws.legacy]
}
}
}$ terraform plan -refresh=false -input=false -lock-timeout=2m -no-color No changes. Your infrastructure matches the configuration.
Checkpoint: Retained resources resolve through the root provider
terraform providers && terraform plan -refresh=false -input=false -lock-timeout=2m -no-colorContinue whenThe child receives the intended alias, the provider error is absent, and no resource is created, destroyed, or replaced.
Stop whenThe plan changes remote objects, points to another provider identity, or still needs the nested configuration.
If this step fails
The child module rejects the providers map
Likely causeThe child did not declare the alias in configuration_aliases or uses another local provider name.
Inspect the child required_providers block.Match keys to the child's expected names.
ResolutionAdd the exact declaration without changing provider source.
The plan proposes replacement after the mapping change
Likely causeProvider settings, region, account, or resource address changed.
Compare provider identities and the prior successful plan.Inspect resource provider documentation for ForceNew attributes.
ResolutionDo not apply; correct the mapping or plan a separate migration.
Security notes
- Validate cloud account and region through a read-only identity command before allowing refresh or apply.
- Do not place provider credentials in module inputs or provider blocks.
Alternatives
- If a module cannot yet be refactored, keep the restored provider configuration temporarily and create a separate tested migration.
Stop conditions
- The plan is not empty or fully explained.
- The child module version differs from the last successful run.
command
For retired resources, create and apply one reviewed destroy plan while the provider remains
Keep the restored module and provider configuration available, remove only the resource blocks approved for retirement, then create a saved plan. Inspect the plan in text and JSON, verify the exact destroy set, obtain approval, and apply that immutable plan. Remove the temporary provider and module only after state proves no associated resources remain.
Why this step matters
HashiCorp's documented orphan-resource recovery is to restore the provider configuration and let Terraform complete the intended lifecycle. A saved plan prevents configuration drift between review and execution, but destruction remains irreversible for many services.
What to understand
Create separate plans for keep and retire branches when possible; do not mix provider repair with broad maintenance.
Inspect terraform show -json with policy tooling to confirm the destroy set and provider identity.
Back up stateful services through their service-specific recovery procedure before approval.
Apply only the reviewed saved plan with terraform apply {{planFile}}. Never regenerate it silently after approval.
After apply, confirm the retired addresses are absent from state and provider reality before removing the temporary provider configuration.
System changes
- The plan file contains sensitive values and must be protected. Applying it destroys only the explicitly reviewed remote objects and updates state.
Syntax explained
-out={{planFile}}- Saves the exact proposed actions for immutable review and later apply.
terraform show -no-color- Renders the saved plan for human review.
terraform apply {{planFile}}- Executes only the reviewed saved plan; this is a separate explicitly approved action.
Values stay on this page and are never sent or saved.
terraform plan -input=false -lock-timeout=5m -out='{{planFile}}' && terraform show -no-color '{{planFile}}'Terraform will perform the following actions:
# module.database.aws_db_parameter_group.legacy will be destroyed
- resource "aws_db_parameter_group" "legacy" {
- name = "legacy-db-params" -> null
}
Plan: 0 to add, 0 to change, 1 to destroy.Checkpoint: The destroy set is exact and recoverable
terraform show -no-color '{{planFile}}'Continue whenOnly owner-approved retired addresses are destroyed; there are zero unexpected additions, changes, or replacements.
Stop whenAny retained, shared, stateful, unknown, or unrelated object appears in the change set.
If this step fails
The plan includes resources outside the retired inventory
Likely causeConfiguration drift or module restoration changed more than provider availability.
Compare plan JSON with the decision record.Restore the last known configuration and re-plan.
ResolutionReject the plan and split the recovery.
The saved plan is stale at apply time
Likely causeState, variables, provider versions, or configuration changed after review.
Compare plan creation metadata and state serial.Check for intervening runs.
ResolutionDiscard it and repeat review; never force a stale plan.
Security notes
- Plan files can contain secrets. Encrypt them, keep them out of Git, and delete them according to policy.
- Require service-specific backups and owner approval before destructive apply.
Alternatives
- Keep the resource managed through the restored provider and schedule retirement later.
Stop conditions
- The service lacks a tested restore.
- The plan includes any unapproved destruction or replacement.
verification
Verify provider ownership, state integrity, and an empty final plan
After the keep migration or approved retirement completes, rerun the provider graph, state inventory, protected metadata extraction, and a normal plan. Compare lineage and serial with the pre-recovery record. The old module-scoped provider address must be absent only after no resource depends on it.
Why this step matters
The absence of the headline error is insufficient. Final evidence must prove that state still has the expected lineage, every retained object remains managed, retired objects are gone by decision, provider mappings are root-owned, and a normal locked plan is coherent.
What to understand
Exit code 0 from detailed-exitcode means no changes; exit 2 requires plan review and exit 1 means failure.
Compare state lineage and serial with the protected pre-recovery note. Explain every serial increase through an approved operation.
Search Terraform providers output and sanitized state metadata for the old module-scoped configuration address.
Add module tests that instantiate every required alias and CI policy that rejects nested provider blocks in reusable modules.
Document decommission order: destroy or migrate resources first, remove provider configurations last.
System changes
- Reads configuration, state metadata, and provider reality through a normal plan. No change is intended.
Syntax explained
-detailed-exitcode- Distinguishes no changes (0), planned changes (2), and errors (1).
-lock-timeout=5m- Retains state locking while allowing routine queue delay.
terraform providers && terraform state list | sort && terraform plan -input=false -detailed-exitcode -lock-timeout=5m -no-colorProviders required by configuration:
.
└── provider[registry.terraform.io/hashicorp/aws] 5.92.0
Providers required by state:
provider[registry.terraform.io/hashicorp/aws]
No changes. Your infrastructure matches the configuration.Checkpoint: Recovery is complete and reproducible
terraform plan -input=false -detailed-exitcode -lock-timeout=5m -no-colorContinue whenThe provider error is absent; exit 0 is preferred, while exit 2 is accepted only for separately reviewed drift unrelated to recovery.
Stop whenLineage changed, serial is unexplained, the old provider address remains, or the plan proposes recreation.
If this step fails
The final plan still reports Provider configuration not present
Likely causeAnother provider address remains orphaned.
Compare all state-only provider addresses.Repeat inventory from the current state.
ResolutionDo not remove any restored provider until all dependents are handled.
The final plan proposes recreating retained resources
Likely causeProvider identity, address, or state association is wrong.
Verify account, region, module instance keys, and providers map.Compare protected state and Git history.
ResolutionFreeze applies and repair the mapping; do not accept replacement as success.
Security notes
- Delete protected state copies and saved plans only according to incident-retention policy.
- Rotate any credentials discovered in history or evidence handling.
Alternatives
- If unrelated drift exists, close provider recovery after proving the mapping and open a separate drift review.
Stop conditions
- The final plan is not understood.
- Any retained object is missing from state or provider reality.
Finish line
Verification checklist
terraform plan -refresh=false -input=false -lock-timeout=2m -no-colorTerraform does not print Error: Provider configuration not present and can build the provider graph.terraform providersEvery provider required by state can be supplied by the reviewed root configuration or explicit module mapping.terraform state list | sortAll KEEP addresses are present and all approved RETIRE addresses are absent.terraform plan -input=false -detailed-exitcode -lock-timeout=5m -no-colorExit 0 means convergence; exit 2 requires a separate reviewed drift plan; exit 1 blocks closure.terraform state pull | jq '{lineage,serial,terraform_version}'Lineage matches the pre-recovery state and each serial increase maps to an approved apply or state update.Recovery guidance
Common problems and safe checks
Terraform prints Error: Provider configuration not present after a module block was deleted
Likely causeThe module contained the provider configuration and resources created by it remain in state.
Inspect the full module and provider address in the error.Restore the module call and original provider configuration from history.
ResolutionRestore provider availability first, then migrate retained resources or destroy retired resources through Terraform.
The provider plugin is installed but Terraform still says Provider configuration not present
Likely causeInstallation satisfies the provider source requirement, not the missing configured instance or alias.
Compare both sections of terraform providers.Inspect aliases and module providers maps.
ResolutionDefine and pass the exact provider configuration address required by state.
Adding a default provider block does not fix the error
Likely causeState expects an aliased or module-scoped configuration, not the implied default.
Copy the alias suffix and module path from the error.Inspect configuration_aliases and parent mappings.
ResolutionRestore the exact alias and scope instead of adding unrelated defaults.
terraform validate reports an undefined provider configuration
Likely causeA module references an alias that the child did not declare or the parent did not map.
Inspect required_providers.configuration_aliases.Inspect the module providers map keys and values.
ResolutionDeclare the alias in the child and map it to a root provider.
The plan proposes resource replacement after provider restoration
Likely causeThe provider identity, region, account, endpoint, or resource address differs from the original.
Compare Git history, provider identity, and state metadata.Use refresh-disabled planning first.
ResolutionStop and correct the configuration; replacement is not an acceptable structural repair.
Several aliases appear only under Providers required by state
Likely causeMultiple provider configurations were removed, perhaps across nested modules.
Extract every provider address from protected state.Inventory resources per address.
ResolutionRecover each exact identity and split owners or lifecycle branches as needed.
terraform state replace-provider appears to succeed but the alias error remains
Likely causeThe command changed a provider source mapping but cannot recreate a missing alias or module-scoped configuration.
Review the from and to source FQNs.Restore the configuration alias and module mapping.
ResolutionTreat the source change as a separate incident and repair the configuration graph.
The module uses count, for_each, or depends_on and contains provider blocks
Likely causeLegacy nested-provider design is incompatible with modern module call patterns.
Review Terraform module provider documentation.List all module instance addresses.
ResolutionMove provider ownership to the root and pass configurations explicitly before expanding module instances.
The original provider configuration used expired credentials
Likely causeConfiguration structure and authentication lifecycle were coupled.
Recover only non-secret settings.Request current approved workload identity for the exact target.
ResolutionDo not restore old secrets; rotate them and validate target identity.
A destroy plan includes a shared production resource
Likely causeThe retired module contains objects with another owner or external dependency.
Compare the plan with the ownership inventory.Review provider reality and service backups.
ResolutionReject the plan and classify the shared resource as KEEP until a separate decommission is approved.
The final state serial changes unexpectedly
Likely causeAnother writer or state operation ran during recovery.
Freeze queues and remote runs.Compare state snapshots, run logs, and provider audit events.
ResolutionEscalate to state reconciliation; do not apply another plan.
The error returns after the temporary provider is removed
Likely causeAt least one state object still references the old configuration.
Run terraform providers and inspect provider bindings.List all dependent resource addresses.
ResolutionReintroduce the provider and complete migration or lifecycle for every dependency.
HCP Terraform works differently from the local shell
Likely causeRemote workspace variables, working directory, credentials, module cache, or execution version differs.
Compare configuration version and workspace settings.Run recovery in the authoritative execution mode.
ResolutionDo not use the local result as proof until contexts match.
State pull cannot be stored under local policy
Likely causeState contains regulated or secret data that may not leave the controlled platform.
Use backend versioning or approved secure analysis.Extract only provider metadata in place.
ResolutionContinue without a local copy only when equivalent protected recovery evidence exists.
Reference
Frequently asked questions
What does Terraform Error: Provider configuration not present mean?
Terraform state still associates a resource with a provider configuration address that the current module graph cannot supply. The provider plugin may be installed, but the required default or aliased configured instance, often at a removed module path, is missing.
Can I delete the resource from state to fix Provider configuration not present?
Not as a shortcut. terraform state rm abandons management while the real object remains. First restore the provider configuration, then migrate retained resources or destroy retired resources through an approved Terraform plan.
Why does adding the provider to required_providers not solve it?
required_providers declares a plugin source and version requirement. The error asks for a concrete provider configuration instance, including its module scope and alias, that supplies settings and authentication.
Can terraform state replace-provider repair a missing alias?
No. state replace-provider changes provider source addresses, such as moving from one registry source to another. It does not recreate an alias or a provider configuration removed from a module.
Should providers live inside child modules?
Reusable child modules should declare provider requirements and configuration_aliases, while root modules own concrete provider configurations and pass them through the providers map. This keeps lifecycle and authentication boundaries visible.
How do I keep existing resources without recreating them?
Restore the exact provider configuration first, then move provider ownership to the root with compatible aliases and module mappings. Require a refresh-disabled plan with no create, destroy, or replacement before applying any state update.
How do I remove an orphaned resource intentionally?
Restore the provider configuration that created it, keep that configuration available, remove only the approved resource definition, review a saved destroy plan, apply that exact plan, verify state and provider reality, then remove the provider configuration last.
Does reintroducing the provider block change infrastructure?
The HCL change alone does not. A later refresh, plan, or apply can contact the provider and may update state or infrastructure, so verify account, region, credentials, and plan before proceeding.
Can I copy the old provider block from Git history?
Recover its non-secret structure, source, alias, region, endpoint, and module path, but never resurrect credentials from history. Use current approved identity and rotate anything that was committed.
Why preserve state before the repair?
State contains the provider associations, lineage, serial, and resource inventory needed to prove the correct recovery and investigate an unexpected plan or concurrent write. Store it as secret-bearing evidence.
What if the final plan proposes changes?
Exit 2 is not automatically a failure, but every change must be separated from the provider repair and reviewed. Unexplained creation, destruction, replacement, or broad drift blocks closure.
How often should this Guide be reviewed?
Review it within 90 days and whenever Terraform module provider inheritance, alias rules, state commands, HCP Terraform execution, CI policy, provider authentication, or supported CLI versions change.
Recovery
Rollback
There is no universal automatic rollback for provider-association repair or destruction. Configuration-only changes can be reverted in Git only before a state-changing apply. After an apply, freeze writers, preserve current and previous state evidence, compare lineage and serial, and reconcile provider reality with configuration. Never push an older state automatically.
- Stop every local, CI, scheduler, and remote Terraform writer for the affected state.
- Preserve current state, the pre-recovery snapshot, plan files, apply log, provider graph, Git commits, and checksums in the restricted incident location.
- If only HCL changed and no apply occurred, revert the recovery commit and reproduce the provider graph before resuming.
- If provider ownership was applied, restore the last known valid root and module provider mappings, then produce a refresh-disabled plan; do not edit provider addresses in raw state.
- If resources were destroyed, use the service-specific backup and restore procedure, then import or re-create management through a separate reviewed recovery plan.
- Do not run terraform state push -force, state rm, import, or replace-provider as an improvised rollback. Each changes ownership semantics and needs its own evidence and approval.
- Close the incident only after lineage, serial, retained addresses, provider identity, and a locked normal plan are coherent.
Evidence