Fix Terraform Provider Version Conflicts
A practical guide to resolving Terraform provider version conflicts and lock file checksum errors across modules, developers, and CI pipelines.
Key takeaways
- Run terraform providers to find the module whose version constraint does not overlap the rest, then widen or align it.
- Use terraform init -upgrade only when you mean to move versions, and run terraform providers lock with every platform your team and CI use, then commit .terraform.lock.hcl so Linux runners stop failing checksums.
On this page
Fix a Terraform provider version conflict by running terraform providers to find the module whose constraint doesn't overlap the others, then aligning it. Fix lock file errors with terraform init -upgrade when the version change is intentional, and fix CI checksum failures with terraform providers lock -platform=linux_amd64 -platform=darwin_arm64, then commit .terraform.lock.hcl.
Verified against
Terraform 1.17.1, hashicorp/aws provider 6.71.0, against the developer.hashicorp.com dependency lock file, version constraints and providers lock pages. Checked October 2026.
These errors are confusing mostly because the message rarely points at the file you need to change. The constraint it complains about can live three modules deep. Once you know how Terraform picks a version and what the lock file records, they stop being mysteries.
How Terraform selects provider versions
Every provider is declared in a required_providers block:
# versions.tf (root module)
terraform {
required_version = ">= 1.10.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 6.0"
}
random = {
source = "hashicorp/random"
version = "~> 3.7"
}
}
}
On terraform init, Terraform collects the constraints for each provider from the root module and every child module, intersects them, and picks the newest version that satisfies all of them. It records the chosen version and its hashes in .terraform.lock.hcl. On later runs it reuses the recorded version instead of re-solving, which keeps two engineers on the same build. Modules themselves are not locked: the docs say Terraform always picks the newest module version matching its constraint, so pin modules with an exact version if you need that.
The operators, per HashiCorp's version constraints page:
= 6.71.0(or bare6.71.0) pins one exact version.>= 6.0allows that version or anything newer.~> 6.40allows only the right-most component to increment:6.41,6.71, but not7.0.~> 6.40.0allows6.40.xpatches only.
The docs' guidance splits by module type: reusable modules should declare only a minimum (>= 6.0) so callers can upgrade freely, and root modules should use ~> to set both bounds. A shared module that pins ~> tightly is the most common cause of the conflict below.
Error 1: "no available releases match the given constraints"
Error: Failed to query available provider packages
Could not retrieve the list of available versions for provider
hashicorp/aws: no available releases match the given constraints ~> 5.0, ~> 6.0
Two places in your dependency tree disagree. Here the root wants ~> 6.0 (AWS provider 6.x, current as of October 2026) while a module still requires ~> 5.0. No version is both, so the solver gives up. Find the culprit:
$ terraform providers
Providers required by configuration:
.
├── provider[registry.terraform.io/hashicorp/aws] ~> 6.0
├── provider[registry.terraform.io/hashicorp/random] ~> 3.7
└── module.vpc
└── provider[registry.terraform.io/hashicorp/aws] ~> 5.0
module.vpc is the odd one out. Upgrade it to a release that supports the newer provider, or, if it's your module, relax its constraint to a minimum like >= 5.0. If it's a third-party module you can't edit, you stay on a version inside its range until it updates, which is often the signal to fork or replace it. For how to version your own shared modules so this doesn't recur, see Terraform module versioning with shared registries.
Error 2: "Inconsistent dependency lock file"
Error: Inconsistent dependency lock file
The following dependency selections recorded in the lock file are
inconsistent with the current configuration:
- provider registry.terraform.io/hashicorp/aws: locked version selection
5.100.0 doesn't match the updated version constraints "~> 6.0"
To update the locked dependency selections to match a changed configuration, run:
terraform init -upgrade
Someone bumped a constraint and the lock file still holds the old selection. Terraform refuses to swap binaries silently. If the bump is intentional:
$ terraform init -upgrade
$ git diff .terraform.lock.hcl
$ git add .terraform.lock.hcl && git commit -m "Upgrade hashicorp/aws to 6.x"
The docs describe -upgrade as ignoring the recorded selections and picking the newest version that matches your constraints. If the change was not intentional (a bad merge of the lock file), restore the file from version control and run a plain terraform init. The same error appears with "required by this configuration but no version is selected" when a new provider was added without re-running init.
Error 3: checksum mismatch on CI
You generate the lock file on a Mac, commit it, and a Linux runner fails:
Error: Failed to install provider
Error while installing hashicorp/aws v6.71.0: the local package for
registry.terraform.io/hashicorp/aws 6.71.0 doesn't match any of the
checksums previously recorded in the dependency lock file
The lock file holds two hash schemes: zh: hashes of the official zip files, and the preferred h1: hash of the package contents. A local init on darwin_arm64 records the h1: hash for that platform only, so the linux_amd64 package has nothing to match. Record every platform you use:
$ terraform providers lock \
-platform=linux_amd64 \
-platform=linux_arm64 \
-platform=darwin_arm64 \
-platform=darwin_amd64 \
-platform=windows_amd64
$ git add .terraform.lock.hcl && git commit -m "Lock provider hashes for all platforms"
The docs note this writes both zh: and h1: checksums for each listed platform. Re-run it whenever you bump a provider, and put the command in a make lock target so nobody forgets.
Commit the lock file, ignore the cache
Commit .terraform.lock.hcl. It is the mechanism that guarantees every developer and pipeline installs identical provider builds; leave it out and one engineer plans against 6.70.0 while another plans against 6.71.0, producing diffs unrelated to the change. Review lock file changes in pull requests, because a changed hash for an unchanged version is a supply-chain red flag, as covered in the Terraform lock file supply-chain attack.
The .terraform/ directory is different. It holds downloaded providers and cached modules, and belongs in .gitignore:
# .gitignore
.terraform/
*.tfstate
*.tfstate.backup
When init stays wedged
If init keeps failing after the constraints and lock file are fixed, the local cache is usually half-installed:
$ rm -rf .terraform/
$ terraform init
Deleting .terraform/ removes only downloaded binaries and cached modules, not your state (for remote backends) or your lock file. If you use a local terraform.tfstate, it sits beside .terraform/, not inside it, so it is safe too. A checksum wall after a clean init means the lock file is missing a platform; re-run the multi-platform lock above.
Where this breaks
Some setups need a different fix. Air-gapped CI with a provider mirror (terraform providers mirror or a provider_installation block) must lock against the mirror's packages, and hashes can differ if the mirror repackages them. Teams running OpenTofu share the lock file format but use a different registry, so don't commit a lock file generated by one tool for the other; Terraform vs OpenTofu covers the split. And if a module genuinely needs an old provider major, no constraint trick helps: you need two root modules or an upgraded module.
Questions people ask
What does "no available releases match the given constraints" mean in Terraform?
Two modules in your configuration ask for provider versions that do not overlap, for example ~> 5.0 and ~> 6.0 for hashicorp/aws. Terraform must pick one version for the whole configuration, so it fails. Run terraform providers to see which module declares each constraint, then upgrade that module or relax its constraint to a minimum version.
Should I commit .terraform.lock.hcl to git?
Yes. HashiCorp recommends committing it so every run installs the same provider versions and verifies them against recorded checksums. Generate it with terraform providers lock for all platforms your team and CI use. Do not commit the .terraform/ directory, which is only a local cache of downloaded providers and modules.
How do I fix a Terraform checksum mismatch in CI?
The lock file was generated on a different OS or CPU, so it lacks the h1: hash for the runner's package. Run terraform providers lock -platform=linux_amd64 -platform=darwin_arm64 (plus any other platforms you use), commit the updated .terraform.lock.hcl, and re-run the pipeline. Only delete the lock file if you also intend to re-review every provider version.
The call we'd make
Use >= x.y minimums in reusable modules and ~> in root modules, commit .terraform.lock.hcl, and gitignore .terraform/. Run terraform providers lock for every platform the day you add or bump a provider, not the day CI breaks. When a conflict appears, run terraform providers before touching anything, and reach for terraform init -upgrade only when you mean to move versions. For init, plan and state failures beyond providers, keep the Terraform error troubleshooting guide handy.
Sources
Cite this article
Kiril Urbonas (2026). Fix Terraform Provider Version Conflicts. DevOpsNess. Updated 2026-10-31. https://www.devopsness.com/blog/fix-terraform-provider-version-conflicts
[Fix Terraform Provider Version Conflicts](https://www.devopsness.com/blog/fix-terraform-provider-version-conflicts) (Kiril Urbonas, DevOpsNess, updated 2026-10-31)
More from DevOps
Explore more articles in this category
15 SRE Interview Questions With Answers, From SLOs to On-Call
SRE interviews test numbers and judgment. Fifteen questions on SLIs, error budgets, incident command, toil, capacity, on-call and postmortems, plus a systems-design scenario, each with the answer that scores and the one that loses the room.
Sign Container Images With Cosign: Keyless GitHub Actions Workflow, SBOM and In-Cluster Checks
One workflow that builds, signs keylessly with GitHub OIDC, attaches an SBOM and SLSA provenance, plus the Kyverno policy that refuses anything unsigned. Copy it, change three names, ship it.
Fix Prometheus High Cardinality: 6 Commands to Find and Drop Bad Series
When Prometheus runs out of memory, one label is almost always to blame. Six commands to find it, the relabel rules that drop it, and the scrape limits that stop it coming back.
You might have missed
Evergreen posts worth revisiting.