kubernetes/kops · error

invalid hash %q - not hex

Error message

invalid hash %q - not hex

What it means

FromString hex-decodes the hash string after a length check; this error is thrown when hex.DecodeString fails, meaning the string contains non-hexadecimal characters. Length was correct for the algorithm, but the content is not valid hex (e.g. contains 'g'-'z', spaces, or base64 data).

Source

Thrown at util/pkg/hashing/hash.go:92

	var l int
	switch ha {
	case HashAlgorithmMD5:
		l = 32
	case HashAlgorithmSHA1:
		l = 40
	case HashAlgorithmSHA256:
		l = 64
	default:
		return nil, fmt.Errorf("unknown hash algorithm: %q", ha)
	}

	if len(s) != l {
		return nil, fmt.Errorf("invalid %q hash - unexpected length %d", ha, len(s))
	}

	hashValue, err := hex.DecodeString(s)
	if err != nil {
		return nil, fmt.Errorf("invalid hash %q - not hex", s)
	}
	return &Hash{Algorithm: ha, HashValue: hashValue}, nil
}

func MustFromString(s string) *Hash {
	h, err := FromString(s)
	if err != nil {
		klog.Fatalf("FromString(%q) failed with %v", s, err)
	}
	return h
}

func FromString(s string) (*Hash, error) {
	for _, ha := range []HashAlgorithm{HashAlgorithmMD5, HashAlgorithmSHA1, HashAlgorithmSHA256} {
		prefix := fmt.Sprintf("%s:", ha)
		if strings.HasPrefix(s, prefix) {
			return ha.FromString(s[len(prefix):])
		}

View on GitHub (pinned to 4c8573c808)

Solutions

  1. Recompute the checksum with the standard tool (sha256sum/sha1sum/md5sum) which always outputs valid lowercase hex
  2. Strip any 'sha256:'/'sha1:' prefix and surrounding whitespace from the hash string
  3. If you have a base64 digest, convert it: `echo <b64> | base64 -d | xxd -p -c 64`

Example fix

// before
h, _ := hashing.HashAlgorithmSHA256.FromString(strings.TrimSpace("sha256:" + digest))
// after
h, _ := hashing.HashAlgorithmSHA256.FromString(strings.TrimPrefix(digest, "sha256:"))
Defensive patterns

Strategy: validation

Validate before calling

func isHexDigest(s string) bool {
	if s == "" { return false }
	_, err := hex.DecodeString(s)
	return err == nil
}
// call before: if !isHexDigest(digest) { return fmt.Errorf("digest must be hex") }

Type guard

func isHexString(s string) bool {
	for _, c := range s {
		if !((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')) {
			return false
		}
	}
	return len(s) > 0
}

Try / catch

h, err := algo.FromString(s)
if err != nil {
	if strings.Contains(err.Error(), "not hex") {
		return fmt.Errorf("checksum %q contains non-hex characters; expected hex output of sha256sum", s)
	}
	return err
}

Prevention

When it happens

Trigger: Calling HashAlgorithm.FromString with a string of the right length but containing non-hex characters, e.g. hashing.HashAlgorithmSHA1.FromString("zz11..."), or accidentally pasting a base64 digest instead of hex.

Common situations: Pasting a base64-encoded checksum (common in some registries) into a field that expects hex; typos like 'O' vs '0' or 'l' vs '1'; hashes with whitespace or prefix like 'sha256:' not stripped.

Related errors


AI-assisted analysis of kubernetes/kops@4c8573c808 (2026-09-05). Data as JSON: /api/errors/50d9a63256f56512. Report an issue: GitHub.