{"record":{"id":"81ddeaeefadd0452","repo":"flipped-aurora/gin-vue-admin","slug":"error-81ddea","errorCode":null,"errorMessage":"整文件校验失败","messagePattern":"整文件校验失败","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/service/media/media_upload.go","lineNumber":140,"sourceCode":"\t\tglobal.GVA_DB.WithContext(ctx).Model(&media.MediaUpload{}).Where(\"id = ?\", uploadID).Update(\"status\", media.UploadStatusFailed)\n\t\treturn m, e\n\t}\n\n\t// 校验分片齐全\n\tvar cnt int64\n\tglobal.GVA_DB.WithContext(ctx).Model(&media.MediaUploadChunk{}).Where(\"upload_id = ?\", uploadID).Count(&cnt)\n\tif int(cnt) != up.ChunkTotal {\n\t\treturn fail(fmt.Errorf(\"分片不全: %d/%d\", cnt, up.ChunkTotal))\n\t}\n\n\t// 合并到临时成品\n\tmerged := filepath.Join(upload.ChunkDir(uploadID), \"merged.bin\")\n\tgotMd5, err := upload.MergeChunks(uploadID, up.ChunkTotal, merged)\n\tif err != nil {\n\t\treturn fail(err)\n\t}\n\tif gotMd5 != up.FileHash {\n\t\treturn fail(errors.New(\"整文件校验失败\"))\n\t}\n\n\t// 经 OSS 接口推到配置存储\n\tfh, cleanup, err := upload.BuildFileHeader(merged, \"file\", up.FileName)\n\tif err != nil {\n\t\treturn fail(err)\n\t}\n\tdefer cleanup()\n\toss := upload.NewOss()\n\turl, key, err := oss.UploadFile(ctx, fh)\n\tif err != nil {\n\t\treturn fail(err)\n\t}\n\n\t// 登记媒体库\n\text := \"\"\n\tif i := strings.LastIndex(up.FileName, \".\"); i >= 0 {\n\t\text = strings.TrimPrefix(up.FileName[i:], \".\")","sourceCodeStart":122,"sourceCodeEnd":158,"githubUrl":"https://github.com/flipped-aurora/gin-vue-admin/blob/3136500ef380842b0eb6c4daa87c3f8a47fcf9e0/server/service/media/media_upload.go#L122-L158","documentation":"After MergeChunks concatenates all chunks into merged.bin and returns its MD5, Complete() compares gotMd5 with the FileHash recorded at session creation. A mismatch returns '整文件校验失败' (whole-file verification failed) via fail(), which also marks the upload failed.","triggerScenarios":"Any chunk was corrupted in transit/storage, a chunk is missing or duplicated, the client-supplied FileHash at Init does not match the actual file bytes, or the file was modified after hashing (client re-generated the file without restarting the session).","commonSituations":"Client computes MD5 of a different file version than the chunks uploaded; chunk upload retried with wrong index order; disk/storage corruption; user edited the file mid-upload; hash algorithm mismatch (MD5 vs SHA256) between client and server.","solutions":["Verify the client's pre-computed hash matches the exact file being chunked (same bytes, same algorithm — MD5 here).","Re-upload the file: create a fresh upload session, re-hash, upload all chunks, then Complete.","Check chunk-level integrity: ensure every chunk uploaded successfully and indexes are correct before calling Complete.","Confirm no process modified merged.bin or the chunk dir between uploads and merge.","Enable per-chunk hash verification on upload to localize the corrupt chunk."],"exampleFix":"// before: hashing before the user finalizes file selection\nconst hash = await md5(await pickFile()) // file may change afterwards\n// after: hash the exact final bytes right before upload\nconst file = await pickFile()\nconst hash = await md5(file) // hash the same File object being chunked\nawait api.initUpload({ fileName: file.name, fileHash: hash, chunkTotal })","handlingStrategy":"validation","validationCode":"// client-side: verify all chunks uploaded and hash the exact final bytes\nconst hash = await md5(file)\nconst allUploaded = chunkResults.every(r => r.ok)\nif (!allUploaded) throw new Error('some chunks failed; do not call Complete')\nif (!hash || hash.length !== 32) throw new Error('invalid md5 hash')","typeGuard":null,"tryCatchPattern":"try {\n  await svc.Complete(ctx, userID, uploadID)\n} catch (err) {\n  if (err.Error() === '整文件校验失败') {\n    // discard session and re-upload with a freshly computed hash\n  } else {\n    throw err\n  }\n}","preventionTips":["Hash the exact file object being chunked, right before upload","Use the same hash algorithm (MD5) the server expects","Verify every chunk upload response before calling Complete","Prevent file modification between hashing and upload completion"],"tags":["upload","integrity","md5","checksum-mismatch"],"backgroundTag":"checksum-mismatch","analyzedSha":"3136500ef380842b0eb6c4daa87c3f8a47fcf9e0","analyzedAt":"2026-08-31T13:50:02.721Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}