hashicorp/nomad · error

invalid digest format

Error message

invalid digest format

What it means

Returned by newChecksumValidatingReader in api/ioutil.go when the digest string does not contain a '=' separator (checked with strings.SplitN(digest, "=", 2)). This library expects digests in 'algorithm=value' form (e.g. 'sha-256=abc123'); anything else is rejected before any hashing is set up.

Source

Thrown at api/ioutil.go:43

	// checksum is the base64 component of checksum
	checksum string

	// hash is the hashing function used to compute the checksum
	hash hash.Hash
}

// newChecksumValidatingReader returns a checksum-validating wrapper reader, according
// to a digest received in HTTP header
//
// 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,

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Verify the digest string passed to newChecksumValidatingReader/Snapshot contains an '=' separator in 'algo=value' form
  2. Log/inspect the raw digest header from the server; strip any quotes or whitespace mangling
  3. Normalize the digest before passing it in, e.g. prefix with 'sha-256=' if only the hash is available
  4. If the server uses an unsupported header form, compute the digest client-side instead

Example fix

// before
r, err := newChecksumValidatingReader(resp.Body, resp.Header.Get("Digest"))
// after
digest := resp.Header.Get("Digest")
if !strings.Contains(digest, "=") {
    digest = "sha-256=" + digest
}
r, err := newChecksumValidatingReader(resp.Body, digest)
Defensive patterns

Strategy: validation

Validate before calling

func digestLooksValid(digest string) bool {
    parts := strings.SplitN(digest, "=", 2)
    return len(parts) == 2 && parts[0] != "" && parts[1] != ""
}

Try / catch

r, err := newChecksumValidatingReader(body, digest)
if err != nil {
    return fmt.Errorf("digest %q rejected: %w", digest, err)
}

Prevention

When it happens

Trigger: Calling Snapshot (or any API path that wires a checksum-validated body reader) with a Content-Digest header or digest argument that has no '=' character, e.g. a bare hex hash 'abc123...' or an empty string.

Common situations: A proxy or middleware strips or rewrites the Content-Digest header; the server sends a checksum in a non-standard format; a custom test harness passes a raw hash value instead of the RFC 3230 digest expression.

Related errors


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