hashicorp/nomad · error

unsupported checksum format

Error message

unsupported checksum format

What it means

Returned by newChecksumValidatingReader in api/ioutil.go when the digest's algorithm part (before '=') is not 'sha-256' or 'sha-512'. The library only implements those two hash algorithms for checksum-validated reads.

Source

Thrown at api/ioutil.go:54

// The digest must be in the format "<algo>=<base64 of hash>" (e.g. "sha-256=gPelGB7...").
//
// When the reader is fully consumed (i.e. EOT is encountered), if the checksum don't match,
// `Read` returns a checksum mismatch error.
func newChecksumValidatingReader(r io.ReadCloser, digest string) (io.ReadCloser, error) {
	parts := strings.SplitN(digest, "=", 2)
	if len(parts) != 2 {
		return nil, errors.New("invalid digest format")
	}

	algo := parts[0]
	var hash hash.Hash
	switch algo {
	case "sha-256":
		hash = sha256.New()
	case "sha-512":
		hash = sha512.New()
	default:
		return nil, errors.New("unsupported checksum format")
	}

	return &checksumValidatingReader{
		r:        r,
		algo:     algo,
		checksum: parts[1],
		hash:     hash,
	}, nil
}

func (r *checksumValidatingReader) Read(b []byte) (int, error) {
	n, err := r.r.Read(b)
	if n != 0 {
		r.hash.Write(b[:n])
	}

	if err == io.EOF || err == io.ErrClosedPipe {
		found := base64.StdEncoding.EncodeToString(r.hash.Sum(nil))

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Check the algorithm prefix of the digest; it must be exactly 'sha-256' or 'sha-512' (case-sensitive)
  2. Configure the server/proxy to emit sha-256 or sha-512 digests
  3. Request a supported digest via the 'Want-Digest' header if the server supports content negotiation
  4. If an unsupported algorithm is unavoidable, disable checksum validation or implement a client-side validator

Example fix

// before
// server sends: Digest: md5=xyz...
r, err := newChecksumValidatingReader(body, digest)
// after
// configure server/proxy to send: Digest: sha-256=...
digest := resp.Header.Get("Digest")
if !strings.HasPrefix(digest, "sha-256=") && !strings.HasPrefix(digest, "sha-512=") {
    return errors.New("server sent unsupported digest algorithm: " + digest)
}
r, err := newChecksumValidatingReader(body, digest)
Defensive patterns

Strategy: validation

Validate before calling

func digestAlgoSupported(digest string) bool {
    algo := strings.SplitN(digest, "=", 2)[0]
    return algo == "sha-256" || algo == "sha-512"
}

Try / catch

r, err := newChecksumValidatingReader(body, digest)
if err != nil && strings.Contains(err.Error(), "unsupported checksum") {
    return fmt.Errorf("server sent digest with unsupported algorithm: %q", digest)
}

Prevention

When it happens

Trigger: Passing a digest like 'md5=...', 'sha1=...', 'sha-256' with different casing ('SHA-256=...'), or any other algorithm prefix to Snapshot / newChecksumValidatingReader.

Common situations: Servers that emit md5 or crc32c digests; RFC 3230 allows the server to choose the algorithm, so a non-HashiCorp-compatible server or proxy can advertise an unsupported algo; case differences after header normalization.

Related errors


AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04). Data as JSON: /api/errors/7f321183a7da8d9a. Report an issue: GitHub.