hashicorp/terraform · error
unsupported hash format (this may require a newer version…
Error message
unsupported hash format (this may require a newer version of Terraform)
What it means
`PackageMatchesHash` switches on `want.Scheme()` and only handles `HashScheme1` (`h1:`) and `HashSchemeZip` (`zh:`). Any other scheme falls into the `default` arm and produces this message, hinting that the running Terraform is older than whatever scheme was introduced. It is a forward-compatibility guard.
Solutions
- Upgrade Terraform/OpenTofu to a version that understands the new hash scheme.
- Remove the unknown hash lines from the lock file and regenerate with `terraform providers lock`.
- Use `PackageMatchesAnyHash` which silently treats unknown schemes as non-matching.
Example fix
// before hashes: - h9:abcdef... # unknown scheme // after: regenerate $ terraform providers lock -platform=linux_amd64
Defensive patterns
Strategy: validation
Validate before calling
// Reject unknown schemes before calling PackageMatchesHash
switch want.Scheme() {
case HashScheme1, HashSchemeZip:
return PackageMatchesHash(loc, want)
default:
log.Printf("[WARN] unknown hash scheme %q; treating as non-match", want.Scheme())
return false, nil
} Type guard
// isKnownScheme narrows to schemes this build understands
func isKnownScheme(s HashScheme) bool {
return s == HashScheme1 || s == HashSchemeZip
} Try / catch
ok, err := PackageMatchesHash(loc, want)
if err != nil && strings.Contains(err.Error(), "unsupported hash format") {
// upgrade required, or treat as non-match
return PackageMatchesAnyHash(loc, []Hash{want})
} Prevention
- Keep Terraform/OpenTofu versions consistent across the team to avoid new schemes.
- Regenerate the lock file after upgrades.
- Use `PackageMatchesAnyHash` where forward compatibility matters.
- Document the hash scheme in use in repo README.
When it happens
Trigger: A `Hash` with an unknown scheme prefix is passed to `PackageMatchesHash`; switch hits the `default` at hash.go:130.
Common situations: A newer Terraform wrote a lock file with a new hash scheme, then an older Terraform reads it; a hand-edited lock file with a typo'd prefix; experimental/custom hash schemes.
Related errors
- provider package doesn't match the any of the expected…
- provider package doesn't match the expected checksum
- this version of Terraform does not support any of the…
- ziphash scheme ("zh:" prefix) is not supported for unpacked…
- action schema not found for action
AI-assisted analysis of hashicorp/terraform@d32a084675 (2026-08-11).
Data as JSON: /api/errors/8b151127214a631e.
Report an issue: GitHub.
Appendix: source
Thrown at internal/getproviders/hash.go:130
switch want.Scheme() {
case HashScheme1:
got, err := PackageHashV1(loc)
if err != nil {
return false, err
}
return got == want, nil
case HashSchemeZip:
archiveLoc, ok := loc.(PackageLocalArchive)
if !ok {
return false, fmt.Errorf(`ziphash scheme ("zh:" prefix) is not supported for unpacked provider packages`)
}
got, err := PackageHashLegacyZipSHA(archiveLoc)
if err != nil {
return false, err
}
return got == want, nil
default:
return false, fmt.Errorf("unsupported hash format (this may require a newer version of Terraform)")
}
}
// PackageMatchesAnyHash returns true if the package at the given location
// matches at least one of the given hashes, or false otherwise.
//
// If it cannot read from the given location, PackageMatchesAnyHash returns an
// error. Unlike the singular PackageMatchesHash, PackageMatchesAnyHash
// considers unsupported hash formats as successfully non-matching, rather
// than returning an error.
//
// PackageMatchesAnyHash can be used only with the two local package location
// types PackageLocalDir and PackageLocalArchive, because it needs to access the
// contents of the indicated package in order to compute the hash. If given
// a non-local location this function will always return an error.
func PackageMatchesAnyHash(loc PackageLocation, allowed []providerreqs.Hash) (bool, error) {
// It's likely that we'll have multiple hashes of the same scheme in
// the "allowed" set, in which case we'll avoid repeatedly re-reading theView on GitHub (pinned to d32a084675)