hashicorp/terraform · error

hash string must start with a scheme keyword followed by a…

Error message

hash string must start with a scheme keyword followed by a colon

What it means

Thrown by ParseHash when the input string does not contain a colon at index >= 1. Hash values are scheme-prefixed (e.g. 'zh:' for zip-hash, 'h1:' for HMAC), so a zero-length scheme or a missing colon is invalid. The returned Hash is NilHash and must not be used.

Solutions

  1. Prefix the digest with the correct scheme (commonly 'zh:' for zip archives, 'h1:' for dir hashing)
  2. Regenerate the lock file with the toolchain so scheme prefixes are emitted
  3. Strip whitespace/newlines from the hash string before parsing

Example fix

// before
h, err := getproviders.ParseHash(strings.TrimSpace(line))
// line = "f3d2..."  (no scheme) -> error

// after
// line = "zh:f3d2..."
h, err := getproviders.ParseHash(strings.TrimSpace(line))
Defensive patterns

Strategy: validation

Validate before calling

// Validate scheme+colon presence before calling ParseHash.
func validHashFormat(s string) bool {
    c := strings.Index(s, ":")
    return c >= 1 // non-empty scheme followed by a colon
}

if !validHashFormat(raw) {
    return fmt.Errorf("hash %q is missing a scheme prefix (e.g. 'zh:', 'h1:')", raw)
}

Type guard

func IsSchemedHash(s string) bool {
    c := strings.Index(s, ":")
    return c >= 1
}

Try / catch

h, err := getproviders.ParseHash(raw)
if err != nil {
    return fmt.Errorf("invalid hash %q: expected '<scheme>:<digest>': %w", raw, err)
}

Prevention

When it happens

Trigger: ParseHash(s) where strings.Index(s, ':') < 1 — i.e. no colon present, or the string begins with a colon (empty scheme).

Common situations: Lock file or checksum list containing a bare hex digest without a scheme prefix; legacy/plain SHA256 pasted in; a malformed 'hashes' entry built by string concatenation that dropped the prefix; upstream lock-file format regression.

Related errors


AI-assisted analysis of hashicorp/terraform@d32a084675 (2026-08-11). Data as JSON: /api/errors/9fa97a7bde5fc0a8. Report an issue: GitHub.

Appendix: source

Thrown at internal/getproviders/providerreqs/hash.go:48

// ParseHash parses the string representation of a Hash into a Hash value.
//
// A particular version of Terraform only supports a fixed set of hash schemes,
// but this function intentionally allows unrecognized schemes so that we can
// silently ignore other schemes that may be introduced in the future. For
// that reason, the Scheme method of the returned Hash may return a value that
// isn't in one of the HashScheme constants in this package.
//
// This function doesn't verify that the value portion of the given hash makes
// sense for the given scheme. Invalid values are just considered to not match
// any packages.
//
// If this function returns an error then the returned Hash is invalid and
// must not be used.
func ParseHash(s string) (Hash, error) {
	colon := strings.Index(s, ":")
	if colon < 1 { // 1 because a zero-length scheme is not allowed
		return NilHash, fmt.Errorf("hash string must start with a scheme keyword followed by a colon")
	}
	return Hash(s), nil
}

// MustParseHash is a wrapper around ParseHash that panics if it returns an
// error.
func MustParseHash(s string) Hash {
	hash, err := ParseHash(s)
	if err != nil {
		panic(err.Error())
	}
	return hash
}

// Scheme returns the scheme of the recieving hash. If the receiver is not
// using valid syntax then this method will panic.
func (h Hash) Scheme() HashScheme {
	colon := strings.Index(string(h), ":")

View on GitHub (pinned to d32a084675)