{"record":{"id":"0df4475e6b5aa74f","repo":"AlistGo/alist","slug":"wrong-sha1-hash","errorCode":null,"errorMessage":"wrong sha1 hash","messagePattern":"wrong sha1 hash","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"drivers/chunker/util.go","lineNumber":248,"sourceCode":"\t\treturn nil, errors.New(\"missing required field\")\n\t}\n\tif *meta.Version < 1 {\n\t\treturn nil, errors.New(\"wrong version\")\n\t}\n\tif *meta.Size < 0 {\n\t\treturn nil, errors.New(\"negative file size\")\n\t}\n\tif *meta.ChunkNum < 1 || *meta.ChunkNum > maxSafeChunkNumber {\n\t\treturn nil, errors.New(\"wrong number of chunks\")\n\t}\n\tif meta.MD5 != \"\" {\n\t\tif _, err := hex.DecodeString(meta.MD5); err != nil || len(meta.MD5) != 32 {\n\t\t\treturn nil, errors.New(\"wrong md5 hash\")\n\t\t}\n\t}\n\tif meta.SHA1 != \"\" {\n\t\tif _, err := hex.DecodeString(meta.SHA1); err != nil || len(meta.SHA1) != 40 {\n\t\t\treturn nil, errors.New(\"wrong sha1 hash\")\n\t\t}\n\t}\n\tif *meta.Version > chunkerMetadataVerion {\n\t\treturn nil, errors.New(\"unknown metadata version\")\n\t}\n\treturn &chunkMetadata{\n\t\tVersion: *meta.Version,\n\t\tSize:    *meta.Size,\n\t\tNChunks: *meta.ChunkNum,\n\t\tMD5:     meta.MD5,\n\t\tSHA1:    meta.SHA1,\n\t\tXactID:  meta.XactID,\n\t}, nil\n}\n\nfunc joinRemotePathWithBase(baseMountPath, logicalPath string) string {\n\tlogicalPath = utils.FixAndCleanPath(logicalPath)\n\tif utils.PathEqual(logicalPath, \"/\") {","sourceCodeStart":230,"sourceCodeEnd":266,"githubUrl":"https://github.com/AlistGo/alist/blob/843d9dc8149126976b2625911e45a4d3ffd6f2f5/drivers/chunker/util.go#L230-L266","documentation":"When the optional sha1 field in metadata is non-empty, it must be exactly 40 hex-decodable characters (a canonical SHA1 digest). Failing hex.DecodeString or length != 40 returns 'wrong sha1 hash'. Like the md5 check, it prevents garbage digests from entering integrity verification.","triggerScenarios":"Metadata with \"sha1\":\"<64-char sha256 hex>\", a 32-char MD5 in the sha1 field, non-hex characters, or a truncated digest. Surfaced whenever the chunker parses that file's metadata.","commonSituations":"Scripts writing SHA256 into the sha1 slot; algorithm renaming in a pipeline; uppercase or prefixed digests ('sha1:abc...').","solutions":["Correct the field to a 40-char lowercase hex SHA1, or blank it out (empty skips validation)","Regenerate metadata by re-uploading the file through the driver","Align your external tooling's digest field names with the metadata schema (md5->32 hex, sha1->40 hex)"],"exampleFix":"// before (metadata file content)\n{\"ver\":1,\"size\":1024,\"nchunks\":2,\"sha1\":\"<64-char sha256>\"}\n// after\n{\"ver\":1,\"size\":1024,\"nchunks\":2,\"sha1\":\"<40-char sha1 hex>\"}","handlingStrategy":"type-guard","validationCode":"if meta.SHA1 != \"\" {\n    if _, err := hex.DecodeString(meta.SHA1); err != nil || len(meta.SHA1) != 40 {\n        return fmt.Errorf(\"sha1 must be 40 hex chars or empty\")\n    }\n}","typeGuard":"func isValidSHA1Field(s string) bool {\n    if s == \"\" { return true }\n    _, err := hex.DecodeString(s)\n    return err == nil && len(s) == 40\n}","tryCatchPattern":null,"preventionTips":["Never store SHA256 (64 hex) in the sha1 slot","Strip algorithm prefixes like 'sha1:' before writing digest fields"],"tags":["chunker","metadata","hash","integrity"],"backgroundTag":null,"analyzedSha":"843d9dc8149126976b2625911e45a4d3ffd6f2f5","analyzedAt":"2026-08-15T12:14:11.722Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}