{"record":{"id":"50d9a63256f56512","repo":"kubernetes/kops","slug":"invalid-hash-q-not-hex","errorCode":null,"errorMessage":"invalid hash %q - not hex","messagePattern":"invalid hash %q - not hex","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"util/pkg/hashing/hash.go","lineNumber":92,"sourceCode":"\tvar l int\n\tswitch ha {\n\tcase HashAlgorithmMD5:\n\t\tl = 32\n\tcase HashAlgorithmSHA1:\n\t\tl = 40\n\tcase HashAlgorithmSHA256:\n\t\tl = 64\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"unknown hash algorithm: %q\", ha)\n\t}\n\n\tif len(s) != l {\n\t\treturn nil, fmt.Errorf(\"invalid %q hash - unexpected length %d\", ha, len(s))\n\t}\n\n\thashValue, err := hex.DecodeString(s)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"invalid hash %q - not hex\", s)\n\t}\n\treturn &Hash{Algorithm: ha, HashValue: hashValue}, nil\n}\n\nfunc MustFromString(s string) *Hash {\n\th, err := FromString(s)\n\tif err != nil {\n\t\tklog.Fatalf(\"FromString(%q) failed with %v\", s, err)\n\t}\n\treturn h\n}\n\nfunc FromString(s string) (*Hash, error) {\n\tfor _, ha := range []HashAlgorithm{HashAlgorithmMD5, HashAlgorithmSHA1, HashAlgorithmSHA256} {\n\t\tprefix := fmt.Sprintf(\"%s:\", ha)\n\t\tif strings.HasPrefix(s, prefix) {\n\t\t\treturn ha.FromString(s[len(prefix):])\n\t\t}","sourceCodeStart":74,"sourceCodeEnd":110,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/util/pkg/hashing/hash.go#L74-L110","documentation":"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).","triggerScenarios":"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.","commonSituations":"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.","solutions":["Recompute the checksum with the standard tool (sha256sum/sha1sum/md5sum) which always outputs valid lowercase hex","Strip any 'sha256:'/'sha1:' prefix and surrounding whitespace from the hash string","If you have a base64 digest, convert it: `echo <b64> | base64 -d | xxd -p -c 64`"],"exampleFix":"// before\nh, _ := hashing.HashAlgorithmSHA256.FromString(strings.TrimSpace(\"sha256:\" + digest))\n// after\nh, _ := hashing.HashAlgorithmSHA256.FromString(strings.TrimPrefix(digest, \"sha256:\"))","handlingStrategy":"validation","validationCode":"func isHexDigest(s string) bool {\n\tif s == \"\" { return false }\n\t_, err := hex.DecodeString(s)\n\treturn err == nil\n}\n// call before: if !isHexDigest(digest) { return fmt.Errorf(\"digest must be hex\") }","typeGuard":"func isHexString(s string) bool {\n\tfor _, c := range s {\n\t\tif !((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')) {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn len(s) > 0\n}","tryCatchPattern":"h, err := algo.FromString(s)\nif err != nil {\n\tif strings.Contains(err.Error(), \"not hex\") {\n\t\treturn fmt.Errorf(\"checksum %q contains non-hex characters; expected hex output of sha256sum\", s)\n\t}\n\treturn err\n}","preventionTips":["Always source checksums from checksum tools or registries that emit hex","Strip 'sha256:'/'sha1:' prefixes and whitespace before use","Watch for base64 digests (contain +, /, =) — convert to hex first","Lint manifest files for characters outside [0-9a-f] in hash fields"],"tags":["hashing","hex","validation"],"backgroundTag":"invalid-hex-string","analyzedSha":"4c8573c808a73d578c5eadc86d410646ea0b0d73","analyzedAt":"2026-09-05T04:13:19.212Z","contentChangedAt":"2026-09-05T04:13:19.212Z","schemaVersion":2},"datasetVersion":"2026-09-12T07:17:12.445Z"}