hashicorp/terraform · error
ziphash scheme ("zh:" prefix) is not supported for unpacked…
Error message
ziphash scheme ("zh:" prefix) is not supported for unpacked provider packages What it means
`PackageMatchesHash` switches on the hash scheme. For `HashSchemeZip` (the legacy `zh:` prefix) it can only compute a comparison if the package location is a `PackageLocalArchive` (a `.zip` file). If the caller passes an unpacked directory (`PackageLocalDir`) but asks to match a `zh:` hash, the zip-hash cannot be computed for unpacked packages and this error is returned.
Solutions
- Regenerate the lock file with current Terraform so it records `h1:` hashes compatible with unpacked packages.
- Install the provider as an archive so the `zh:` comparison is valid, or switch the lock entries from `zh:` to `h1:`.
- Use `PackageMatchesAnyHash` where unsupported schemes are treated as non-matching instead of erroring.
Example fix
// before: lock pins zh: hash, cache is unpacked dir PackageMatchesHash(PackageLocalDir(p), zhHash) // -> error // after: regenerate lock with h1: hashes terraform providers lock -platform=linux_amd64 // then PackageMatchesHash(PackageLocalDir(p), h1Hash) succeeds
Defensive patterns
Strategy: validation
Validate before calling
// Only request zh: matching for archive locations
switch loc := loc.(type) {
case PackageLocalArchive:
return PackageMatchesHash(loc, want) // zh: ok
default:
if want.Scheme() == HashSchemeZip {
// recompute as h1: or skip
return false, nil
}
return PackageMatchesHash(loc, want)
} Type guard
// canMatchZipHash reports whether loc can be matched against a zh: hash
func canMatchZipHash(loc PackageLocation) bool {
_, ok := loc.(PackageLocalArchive)
return ok
} Try / catch
ok, err := PackageMatchesHash(loc, want)
if err != nil && strings.Contains(err.Error(), "ziphash scheme") {
// fall back to any-hash matching which tolerates the mismatch
return PackageMatchesAnyHash(loc, []Hash{want})
} Prevention
- Prefer `h1:` hashes in lock files; they work for both archives and unpacked dirs.
- Regenerate lock files with the Terraform version actually in use.
- Use `PackageMatchesAnyHash` for tolerant comparison.
- Avoid mixing legacy `zh:` and modern `h1:` schemes in one lock file.
When it happens
Trigger: `PackageMatchesHash(loc, want)` is called where `want.Scheme() == HashSchemeZip` and `loc` is not a `PackageLocalArchive` (e.g. it is a `PackageLocalDir`); the type assertion at hash.go:119 fails.
Common situations: A lock file pins `zh:` hashes but the provider cache holds an unpacked directory; mixing the legacy `zh:` scheme with the modern unpacked-package layout; lock file generated by an older Terraform against an archive-only install.
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…
- unsupported hash format (this may require a newer version…
- archive has incorrect checksum
AI-assisted analysis of hashicorp/terraform@d32a084675 (2026-08-11).
Data as JSON: /api/errors/c77e733794f38842.
Report an issue: GitHub.
Appendix: source
Thrown at internal/getproviders/hash.go:122
// if others are introduced in future PackageMatchesHash may accept multiple
// formats, and may generate errors for any formats that become obsolete.
//
// PackageMatchesHash 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 PackageMatchesHash(loc PackageLocation, want providerreqs.Hash) (bool, error) {
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.View on GitHub (pinned to d32a084675)