flipped-aurora/gin-vue-admin · error

整文件校验失败

Error message

整文件校验失败

What it means

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.

Source

Thrown at server/service/media/media_upload.go:140

		global.GVA_DB.WithContext(ctx).Model(&media.MediaUpload{}).Where("id = ?", uploadID).Update("status", media.UploadStatusFailed)
		return m, e
	}

	// 校验分片齐全
	var cnt int64
	global.GVA_DB.WithContext(ctx).Model(&media.MediaUploadChunk{}).Where("upload_id = ?", uploadID).Count(&cnt)
	if int(cnt) != up.ChunkTotal {
		return fail(fmt.Errorf("分片不全: %d/%d", cnt, up.ChunkTotal))
	}

	// 合并到临时成品
	merged := filepath.Join(upload.ChunkDir(uploadID), "merged.bin")
	gotMd5, err := upload.MergeChunks(uploadID, up.ChunkTotal, merged)
	if err != nil {
		return fail(err)
	}
	if gotMd5 != up.FileHash {
		return fail(errors.New("整文件校验失败"))
	}

	// 经 OSS 接口推到配置存储
	fh, cleanup, err := upload.BuildFileHeader(merged, "file", up.FileName)
	if err != nil {
		return fail(err)
	}
	defer cleanup()
	oss := upload.NewOss()
	url, key, err := oss.UploadFile(ctx, fh)
	if err != nil {
		return fail(err)
	}

	// 登记媒体库
	ext := ""
	if i := strings.LastIndex(up.FileName, "."); i >= 0 {
		ext = strings.TrimPrefix(up.FileName[i:], ".")

View on GitHub (pinned to 3136500ef3)

Solutions

  1. Verify the client's pre-computed hash matches the exact file being chunked (same bytes, same algorithm — MD5 here).
  2. Re-upload the file: create a fresh upload session, re-hash, upload all chunks, then Complete.
  3. Check chunk-level integrity: ensure every chunk uploaded successfully and indexes are correct before calling Complete.
  4. Confirm no process modified merged.bin or the chunk dir between uploads and merge.
  5. Enable per-chunk hash verification on upload to localize the corrupt chunk.

Example fix

// before: hashing before the user finalizes file selection
const hash = await md5(await pickFile()) // file may change afterwards
// after: hash the exact final bytes right before upload
const file = await pickFile()
const hash = await md5(file) // hash the same File object being chunked
await api.initUpload({ fileName: file.name, fileHash: hash, chunkTotal })
Defensive patterns

Strategy: validation

Validate before calling

// client-side: verify all chunks uploaded and hash the exact final bytes
const hash = await md5(file)
const allUploaded = chunkResults.every(r => r.ok)
if (!allUploaded) throw new Error('some chunks failed; do not call Complete')
if (!hash || hash.length !== 32) throw new Error('invalid md5 hash')

Try / catch

try {
  await svc.Complete(ctx, userID, uploadID)
} catch (err) {
  if (err.Error() === '整文件校验失败') {
    // discard session and re-upload with a freshly computed hash
  } else {
    throw err
  }
}

Prevention

When it happens

Trigger: 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).

Common situations: 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.

Related errors


AI-assisted analysis of flipped-aurora/gin-vue-admin@3136500ef3 (2026-08-31). Data as JSON: /api/errors/81ddeaeefadd0452. Report an issue: GitHub.