hashicorp/terraform · error · ErrInvalidSHA256Hash

ErrInvalidSHA256Hash

ErrInvalidSHA256Hash

Error message

the value was not a valid SHA-256 hash

What it means

ErrInvalidSHA256Hash is a sentinel returned by SHA256FromHex when the supplied string cannot be decoded as hex, or decodes to a length other than sha256.Size (32 bytes / 64 hex chars). It guards the parser used to turn the textual SHA256SUMS lines into a SHA256Hash, so a malformed hash line bubbles up as 'failed to parse checksums' from ParseChecksums.

Source

Thrown at internal/releaseauth/hash.go:19

// Copyright IBM Corp. 2014, 2026
// SPDX-License-Identifier: BUSL-1.1

package releaseauth

import (
	"bytes"
	"crypto/sha256"
	"encoding/hex"
	"errors"
	"fmt"
	"log"
)

// SHA256Hash represents a 256-bit SHA hash
type SHA256Hash [sha256.Size]byte

// ErrInvalidSHA256Hash is returned when the hash is invalid
var ErrInvalidSHA256Hash = errors.New("the value was not a valid SHA-256 hash")

// SHA256FromHex decodes a SHA256Hash from a hex string dump
func SHA256FromHex(hashHex string) (SHA256Hash, error) {
	var result [sha256.Size]byte
	hash, err := hex.DecodeString(hashHex)
	if err != nil || len(hash) != sha256.Size {
		return result, ErrInvalidSHA256Hash
	}

	if copy(result[:], hash) != sha256.Size {
		panic("could not copy hash value")
	}

	return result, nil
}

// SHA256Checksums decodes a file generated by the sha256sum program
type SHA256Checksums map[string]SHA256Hash

View on GitHub (pinned to c9def3e214)

Solutions

  1. Re-fetch the genuine SHA256SUMS file from the publisher (hashicorp/releases) and ensure it is the verbatim `<64 lowercase hex> <name>` format.
  2. Validate each hash token is exactly 64 lowercase hex characters before parsing.
  3. If the sums come from a custom mirror, fix the mirror to serve the unmodified upstream file.
  4. Check the file wasn't CRLF-converted or re-encoded on the way through a proxy.

Example fix

// validate a hex hash before calling SHA256FromHex
func validSHA256Hex(s string) bool {
    if len(s) != 64 { return false }
    for _, r := range s {
        if !((r >= '0' && r <= '9') || (r >= 'a' && r <= 'f')) { return false }
    }
    return true
}
Defensive patterns

Strategy: validation

Validate before calling

// Validate hex before parsing.
func validSHA256Hex(s string) bool {
    if len(s) != 64 { return false }
    _, err := hex.DecodeString(s)
    return err == nil
}
if !validSHA256Hex(token) { return errors.New("malformed sha256") }

Type guard

func isInvalidSHA256Hash(err error) bool {
    return errors.Is(err, releaseauth.ErrInvalidSHA256Hash)
}

Try / catch

h, err := releaseauth.SHA256FromHex(raw)
if errors.Is(err, releaseauth.ErrInvalidSHA256Hash) {
    // skip / reject the malformed sums line rather than aborting the whole file
    continue
}

Prevention

When it happens

Trigger: Returned at internal/releaseauth/hash.go:26 when hex.DecodeString(hashHex) errors OR len(hash) != sha256.Size. ParseChecksums (line 51) wraps it: 'failed to parse checksums: %w'.

Common situations: A SHA256SUMS file that is not in the standard `<64-hex> <filename>` format (extra whitespace, wrong separator, base64). A truncated or hand-edited sums file. A sums file from a different algorithm (SHA1/MD5). A registry/mirror that reformatted the file. An empty or garbage response served in place of SHA256SUMS.

Related errors


AI-assisted analysis of hashicorp/terraform@c9def3e214 (2026-08-07). Data as JSON: /api/errors/a737cce9eb7847f6. Report an issue: GitHub.