Terraform: "Error: Provider configuration not present" when using multiple providers

(Cross-posted to Stack Overflow, for better answer-ranking software.)

Summary

I’m trying to migrate from a single default provider for one AWS region to multiple aliased providers for each AWS region that’s in use for my AWS account. I need to know what I can change the Terraform state JSON to to get Terraform to know which resources apply to which provider instances mentioned in the Terraform HCL configuration.

Version

$ terraform --version
Terraform v1.7.0
on darwin_arm64
+ provider registry.terraform.io/hashicorp/aws v5.31.0

Specifics

I currently have the following Terraform state file, generated when Terracognita imported the state for a single AWS region:

# ./terraform.tfstate
{
  "version": 4,
  "terraform_version": "1.6.5",
  "serial": 1008,
  "lineage": "fdc76586-c01b-226a-e481-a73218d5c118",
  "outputs": {},
  "resources": [
    {
      "mode": "managed",
      "type": "aws_instance",
      "name": "name_of_aws_instance",
      "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]",
    ...
    }
}

Where the value of provider is currently for the default provider instance of aws. I’m trying to merge the state of several different AWS regions in to the same Terraform state file, by adding the following per-AWS-region aliased provider instances in Terraform configuration code: (where the text: <aws_region> is actually replaced with an AWS region, such as: us-east-1)

# ./provider.tf
provider "aws" {
  alias = "<aws_region>"
  region = "<aws_region>"
}

All of the resources for a particular AWS region are in *.tf files in the following directories:

./<aws_region>/

And the modules are instantiated with the following entries:

# ./aws_region_module_instances.tf
module "provider_<aws_region>" {
  source = "./<aws_region>"
  providers = {
    aws = aws.<aws_region>
  }
}

With code for the aws_instance in this file:

# ./us-east-1/ec2.tf
resource "aws_instance" "name_of_aws_instance" {
  provider = aws.us-east-1
  ...
}

If I add a property: provider = aws.us-east-1 to the HCL code for the resource "aws_instance" "name_of_aws_instance" entity, thus changing its provider, what should the provider field be set to in the terraform.tfstate JSON for the local Terraform state?

Note that the provider field in the terraform.tfstate file is currently set to:

provider[\"registry.terraform.io/hashicorp/aws\"]

And changing it to any of the following doesn’t work:

  • provider[\"registry.terraform.io/hashicorp/aws\"].us-east-1
  • module.provider_us-east-1.provider[\"registry.terraform.io/hashicorp/aws\"].us-east-1
  • aws.us-east-1

And renders the same error when invoking terraform validate:

│ Error: Provider configuration not present
│
│ To work with module.provider_us-east-1.aws_instance.name_of_aws_instance its original provider configuration at
│ module.provider_us-east-1.provider["registry.terraform.io/hashicorp/aws"].us-east-1 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 module.provider_us-east-1.aws_instance.name_of_aws_instance, after which you can
│ remove the provider configuration again.

Hi @nhooey,

Configuration is the primary source for associating providers and resources, so if the configuration is correct you should not need to manipulate the provider in the state at all. The reason for tracking that provider field carefully, is so that if the resource were removed from the configuration, Terraform knows which provider to use for the deletion.

As for the details, the address of the provider is the actual source of the provider configuration which created the resource, and it won’t necessarily have the same module address, or even the same alias as seen in the resource block. Providers are typically passed in from the root module, so their name in the root module is what you would expect to see in that location.

Another option here would be to use moved blocks or the state mv command to manipulate the state for you, as. that will clear out the old provider field and use the newly configured provider.

@jbardin: Sure, but no matter what you do with terraform state mv, the end result is that terraform.tfstate has a different value for the provider key. There seems to be no other state that is stored.

What should the terraform.tfstate file contain, given the configuration that I’ve shown?

The terraform state list command is already pretty naive, in that it doesn’t mention providers at all, regardless of the value of the provider key in terraform.tfstate.

This whole part of Terraform seems half-implemented and difficult to troubleshoot because it doesn’t tell you what’s happening.

The value in the state is irrelevant as long as there is a corresponding configuration. It’s only when there is no configuration that the state provider value takes precedence. The new configuration value will be written to the state at the next apply.

You haven’t supplied a complete configuration, so I can’t determine exactly where the provider would be located. Since there are no providers being passed into the module, that would usually indicate that the default, un-aliased provider in the root module is used (which appears to be what is set in the state).

I added the following to the original post:

That refers to the local name within the module but not the source of the configured provider. Providers should not be configured within modules, and are typically passed in from the root module.

If aws.us-east-1 does refer to an actual provider configuration within the module (not just one of the local configuration_aliases, and it would output a warning in the CLI), then the provider would be something akin to module.provider_us-east-1.provider["registry.terraform.io/hashicorp/aws"].us-east-1, however since the config validation fails, it indicates that provider configuration does not exist.

I’ve updated all of the filenames in the original post, so it should be clear what is defined and where. I’m still getting the same error as in the original post, and deleting the terraform.tfstate file has no effect. So you were right about the state being irrelevant.

Here is the output of terraform providers:

$ terraform providers

Providers required by configuration:
.
├── provider[registry.terraform.io/hashicorp/aws] ~> 5.31.0
├── module.provider_us-east-1
│   └── provider[registry.terraform.io/hashicorp/aws] ~> 5.31.0

Providers required by state:

    provider[registry.terraform.io/hashicorp/aws]

@jbardin: The providers are defined in the root module in ./provider.tf, and passed in to the modules with the providers = { ... } directive in the module instances.

Do you know why I would still be getting this error?

Never mind, I got it working by removing the provider = aws.<aws_region> properties from all resources in each AWS region module subdirectory, since it’s not necessary when the default provider is being set in the module instantiation.

These Terraform error messages are extremely bad and really throw me off.