Terraform Lock File Viewer

Read the lock file and get the answer to the question it usually raises: why does init work here and fail in CI? It is almost always which kind of hash is recorded.

Paste below, or drop a file anywhere on this panel

Or drop a file anywhere on this panel. Nothing is uploaded: the analysis runs in this tab.

The answer appears here

Paste on the left and press Read. Nothing leaves this tab.

Examples

Real input you can load into the tool above. Each one shows a different thing going wrong, because that is what the tool is for.

Locally computed hashes only

Tied to the machine that ran init, so another platform fails the checksum

provider "registry.terraform.io/hashicorp/aws" {
  version     = "5.31.0"
  constraints = "~> 5.0"
  hashes      = ["h1:abc"]
}

A version its own constraint excludes

The constraint was tightened without re-running init, so the two disagree

provider "registry.terraform.io/hashicorp/aws" {
  version     = "4.67.0"
  constraints = "~> 5.0"
  hashes      = ["zh:abc", "h1:def"]
}

Common mistakes

These are the ones that fail silently. The config is accepted, nothing raises an error, and the consequence arrives later.

  1. Gitignoring the lock file

    It is the record of which provider versions were actually used. Without it two people applying the same configuration can get different providers, and nothing shows why the results differ.

    Instead:Commit it. Check that .gitignore says .terraform/ with a trailing slash rather than .terraform*.

  2. Running init on one OS and expecting CI to work

    init records h1 hashes only for the platform it ran on, so a Linux runner reading a Mac-written lock file fails the checksum. The error looks like a supply-chain warning.

    Instead:Run terraform providers lock with a -platform flag for every platform you use, and commit the result.

  3. Deleting the lock file to fix a checksum error

    It removes the evidence and the pinning at once, so the next init silently selects whatever is newest and the problem comes back on the next machine.

    Instead:Add the missing platform with terraform providers lock -platform=... instead.

There are two kinds of hash in here and only one of them travels

This one distinction explains the checksum errors that appear when a different machine runs init on a configuration that has worked for months.

zh comes from the registry and covers every platform

A zh entry is the SHA256 of an official release archive, taken from the registry's signed checksum list. Terraform records all of them when it can verify the signature, so a lock file with zh hashes works on any platform.

h1 is computed locally and covers only what was installed

An h1 entry is a hash of the extracted package, computed on the machine that ran init. It exists only for the platforms that machine downloaded. A lock file with h1 entries and no zh entries is tied to the operating system that wrote it, and init elsewhere fails with a checksum mismatch that reads like tampering.

The fix is providers lock with explicit platforms

terraform providers lock -platform=linux_amd64 -platform=darwin_arm64 -platform=windows_amd64 records hashes for each, and the result is committed. Run it whenever a provider is added or upgraded, listing whatever your CI runners and your laptops actually are.

This file must be committed

It is the only record of which provider versions were used, and the only thing that stops two people getting different providers from identical configuration. The usual reason it is missing is a .gitignore with .terraform* rather than .terraform/, which catches this file as collateral.

An entry with no constraints line was inferred

Terraform worked the provider out from resource type names rather than being told. It works, and nothing in the configuration states which versions are acceptable, so the next init can select anything.

A locked version outside its own constraint blocks planning

Somebody tightened the constraint without re-running init, so the two disagree. terraform init -upgrade selects a version inside the new constraint and rewrites the entry.