How to Fix Terraform 'Error: no matching provider' Version Conflicts in .terraform.lock.hcl
Threat/Impact Level: HIGH | Exploitability/Downtime Risk: HIGH | Time to Fix: 10 mins
TL;DR
- What broke: Terraform cannot resolve a provider because the version constraint in
required_providersconflicts with what is cached in.terraform.lock.hclor what is available on the Terraform Registry. - How to fix it: Align the
versionconstraint in yourrequired_providersblock with an actually published provider release, then runterraform init -upgradeto regenerate the lock file. - Fast path: Use our Client-Side Sandbox below to auto-refactor this — paste your
required_providersblock and lock file, and get the corrected constraints without sending secrets anywhere.
The Incident (What Does the Error Mean?)
You ran terraform plan and got this:
Error: Failed to query available provider packages
│ Could not retrieve the list of available versions for provider
│ hashicorp/aws: no matching version was found in registry.terraform.io
│ for constraints "~> 6.0"
or this variant when the lock file is stale:
Error: no matching provider
│ The lock file does not include a valid checksum for provider
│ registry.terraform.io/hashicorp/aws 5.58.0 on linux_amd64.
│ Run "terraform init" to update the lock file.
Immediate consequence: terraform plan and terraform apply are completely blocked. No infrastructure changes can be previewed or deployed. In a CI/CD pipeline this surfaces as a hard pipeline failure on every run until manually resolved. If this is gating a hotfix deployment, you are in an outage window.
The Attack Vector / Blast Radius
This is not just a nuisance error. The blast radius is significant:
- Stale lock file in version control: A
.terraform.lock.hclcommitted with checksums for provider version4.xwhilerequired_providersnow pins~> 5.0means every engineer and every CI runner is broken simultaneously on first checkout. There is no graceful degradation. - Overly tight upper-bound pinning: A constraint like
version = "= 4.67.0"will hard-fail the moment HashiCorp yanks or deprecates that patch release from the registry — which has happened. - Cascading module failures: If the broken provider constraint lives inside a child module consumed via
source, the error surfaces in the root module with a confusing stack trace that obscures the real origin. Engineers waste 30+ minutes hunting the wrong file. - Registry proxy / Artifactory mirror misconfiguration: In air-gapped enterprise environments using a private registry mirror, a version that exists on
registry.terraform.iomay simply not have been mirrored yet. The error message is identical, making diagnosis harder. - Mixed provider source addresses: Renaming
hashicorp/kubernetesto a custom fork mid-project without updating the lock file causes checksum validation to fail silently or with the same generic error.
How to Fix It
Basic Fix
The fastest resolution for the majority of cases:
# versions.tf
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
- version = "~> 6.0" # No 6.x release exists as of mid-2025
+ version = "~> 5.0" # Pins to latest stable 5.x, allows patch upgrades
}
}
- required_version = ">= 1.0"
+ required_version = ">= 1.5.0"
}
Then regenerate the lock file:
# Wipe stale lock file entries and re-resolve
terraform init -upgrade
# Verify what got locked
cat .terraform.lock.hcl
Commit the updated .terraform.lock.hcl immediately.
Enterprise Best Practice
For teams managing multiple workspaces, modules, and air-gapped registries:
1. Use pessimistic constraint operators correctly:
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
- version = ">= 4.0, < 6.0" # Too wide — allows breaking major versions
+ version = "~> 5.58" # Allows 5.58.x patch releases only
}
kubernetes = {
source = "hashicorp/kubernetes"
- version = "= 2.27.0" # Hard pin — breaks when release is yanked
+ version = "~> 2.27" # Allows 2.27.x patches, safe floor
}
}
}
2. For private registry mirrors (Artifactory / Nexus), add a terraform.rc or ~/.terraformrc:
+provider_installation {
+ network_mirror {
+ url = "https://your-artifactory.internal/terraform-providers/"
+ include = ["registry.terraform.io/hashicorp/*"]
+ }
+ direct {
+ exclude = ["registry.terraform.io/hashicorp/*"]
+ }
+}
Then sync the missing provider version to your mirror before running terraform init.
3. Multi-platform lock file generation (required if CI runs on linux_amd64 but developers use darwin_arm64):
terraform providers lock \
-platform=linux_amd64 \
-platform=darwin_arm64 \
-platform=windows_amd64
This pre-populates checksums for all platforms in .terraform.lock.hcl, preventing the checksum mismatch variant of this error.
💡 Tired of pasting proprietary configs into ChatGPT? Generic AI tools log your company's ARNs, DB strings, and private keys. StackEngine is a zero-backend, pure Client-Side WASM utility. Drop your failing config into the sandbox above. We redact your secrets locally in the browser and auto-generate the refactored code using your own API key.
Prevention in CI/CD
1. Enforce lock file freshness in CI:
# .github/workflows/terraform.yml
- name: Terraform Init (strict lock)
run: terraform init -lockfile=readonly
# Fails the pipeline if .terraform.lock.hcl is out of sync with required_providers
The -lockfile=readonly flag is the single most effective guard. It prevents silent lock file regeneration in CI and forces engineers to commit updated lock files locally first.
2. Checkov policy to flag unconstrained providers:
checkov -d . --check CKV_TF_1 # Enforces pinned provider source hashes
3. tflint with the Terraform ruleset:
tflint --enable-rule=terraform_required_providers
tflint --enable-rule=terraform_required_version
This catches missing version attributes in required_providers before they reach the registry.
4. Renovate Bot / Dependabot for automated provider bumps:
Configure Renovate with a terraform manager so provider version PRs are raised automatically with changelog links — eliminating the scenario where constraints drift so far from published releases that no matching version exists.
// renovate.json
{
"terraform": {
"enabled": true,
"rangeStrategy": "bump"
}
}
5. OPA/Conftest policy (advanced):
# policy/provider_version.rego
package terraform
deny[msg] {
provider := input.configuration.provider_config[_]
not provider.version_constraint
msg := sprintf("Provider '%v' has no version constraint.", [provider.name])
}
Run in CI with conftest test --policy policy/ plan.json against the JSON-formatted terraform plan output.