{"record":{"id":"3c42de2b127e1b12","repo":"router-for-me/CLIProxyAPI","slug":"line-d-invalid-sha256-w","errorCode":null,"errorMessage":"line %d: invalid sha256: %w","messagePattern":"line (.+?): invalid sha256: %w","errorType":"http","errorClass":null,"httpStatus":502,"severity":"error","filePath":"internal/pluginstore/checksum.go","lineNumber":26,"sourceCode":")\n\nfunc ParseChecksums(data []byte) (map[string]string, error) {\n\tout := map[string]string{}\n\tfor lineNumber, rawLine := range strings.Split(string(data), \"\\n\") {\n\t\tline := strings.TrimSpace(rawLine)\n\t\tif line == \"\" || strings.HasPrefix(line, \"#\") {\n\t\t\tcontinue\n\t\t}\n\t\tfields := strings.Fields(line)\n\t\tif len(fields) < 2 {\n\t\t\treturn nil, fmt.Errorf(\"line %d: invalid checksum entry\", lineNumber+1)\n\t\t}\n\t\thash := strings.ToLower(strings.TrimSpace(fields[0]))\n\t\tif len(hash) != sha256.Size*2 {\n\t\t\treturn nil, fmt.Errorf(\"line %d: invalid sha256 length\", lineNumber+1)\n\t\t}\n\t\tif _, errDecode := hex.DecodeString(hash); errDecode != nil {\n\t\t\treturn nil, fmt.Errorf(\"line %d: invalid sha256: %w\", lineNumber+1, errDecode)\n\t\t}\n\t\tname := strings.TrimPrefix(strings.TrimSpace(fields[1]), \"*\")\n\t\tout[name] = hash\n\t}\n\treturn out, nil\n}\n\nfunc VerifyChecksum(name string, data []byte, checksums map[string]string) error {\n\texpected := strings.ToLower(strings.TrimSpace(checksums[name]))\n\tif expected == \"\" {\n\t\treturn fmt.Errorf(\"checksum for %s not found\", name)\n\t}\n\tactualBytes := sha256.Sum256(data)\n\tactual := hex.EncodeToString(actualBytes[:])\n\tif actual != expected {\n\t\treturn fmt.Errorf(\"checksum mismatch for %s\", name)\n\t}\n\treturn nil","sourceCodeStart":8,"sourceCodeEnd":44,"githubUrl":"https://github.com/router-for-me/CLIProxyAPI/blob/78f0c4079e3e6273d65d03b5549cffc898703264/internal/pluginstore/checksum.go#L8-L44","documentation":"The hash field is 64 characters long but contains non-hex characters, so hex.DecodeString fails and ParseChecksums wraps that error with the line number. This catches look-alike corruption: 'O'/'l' substituted for 0/1, stray punctuation, or encoding damage, despite the length passing.","triggerScenarios":"A checksum line whose first field is 64 chars but includes characters outside [0-9a-f], e.g. a hash pasted from a font/rendering that substituted glyphs, or corrupted during file transfer.","commonSituations":"Copy-paste from a webpage that typographically altered characters; file transferred through a non-binary-safe channel; hand-typed hash with a typo like 'g' or 'O'.","solutions":["Re-copy the hash from the authoritative source without alteration","Regenerate the checksums file directly on the artifacts with sha256sum","Check the file encoding for introduced artifacts (smart quotes, BOM, CRLF mid-line)"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"func hashIsHex64(h string) bool {\n    if len(h) != 64 { return false }\n    for _, c := range h {\n        if !((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f')) { return false }\n    }\n    return true\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Copy hashes programmatically or regenerate them; avoid retyping digests by hand","Transfer checksums files in binary mode / over TLS to avoid glyph and encoding corruption"],"tags":["checksum","hex","plugin-store","corruption"],"backgroundTag":null,"analyzedSha":"78f0c4079e3e6273d65d03b5549cffc898703264","analyzedAt":"2026-08-15T12:26:37.444Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}