flipped-aurora/gin-vue-admin · error

分片不全: %d/%d

Error message

分片不全: %d/%d

What it means

Complete finalizes a chunked upload: it counts recorded MediaUploadChunk rows for the upload session and compares to the session's ChunkTotal. If fewer chunks are recorded than expected it returns "分片不全: %d/%d" (chunks incomplete: got/total) via the fail() path without merging. Note the Count error is ignored, so this message also fires when the count query itself fails.

Source

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

		Where("id = ? AND status = ?", uploadID, media.UploadStatusUploading).
		Update("status", media.UploadStatusMerging)
	if res.Error != nil {
		return m, res.Error
	}
	if res.RowsAffected == 0 {
		return m, errors.New("上传不在可合并状态(可能已在合并或已完成)")
	}

	fail := func(e error) (media.FileUploadAndDownload, error) {
		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()

View on GitHub (pinned to 3136500ef3)

Solutions

  1. List uploaded chunk indexes and upload only the missing ones, then call Complete again
  2. Fix client logic to await all chunk PUTs (Promise.all) before calling Complete
  3. Handle chunk-level failures: any chunk rejected (e.g. hash mismatch) must be retried before Complete
  4. Confirm the client uses the same uploadID returned at session creation for every chunk and the Complete call
  5. Investigate DB errors if all chunks were actually uploaded — the Count error is ignored, so a DB outage surfaces as this message

Example fix

// before
chunks.forEach(c => upload(c))
await complete(uploadId)
// after
await Promise.all(chunks.map(c => upload(c)))
await complete(uploadId)
Defensive patterns

Strategy: validation

Validate before calling

// client: verify all chunks acknowledged before completing
const acked = await listUploadedChunks(uploadId)
if (acked.length !== chunkTotal) {
    const missing = diff(range(chunkTotal), acked)
    await Promise.all(missing.map(i => uploadChunk(uploadId, i)))
}

Try / catch

if err := svc.Complete(ctx, uploadID, meta); err != nil {
    if strings.Contains(err.Error(), "分片不全") {
        // parse got/total, re-upload missing chunk indexes, then retry Complete
        return reconcileAndComplete(uploadID)
    }
    return err
}

Prevention

When it happens

Trigger: Calling Complete before all chunks have been uploaded (some indexes never sent), a chunk rejected by MD5 validation (error 438) leaving a gap, chunks written to a different uploadID, or a DB error making Count return 0 — all raise this from media_upload.go:130.

Common situations: Frontend firing Complete optimistically before the last parallel chunk request resolves; a failed/corrupt chunk silently skipped by the client; retries creating a new uploadID while Complete uses the old one; DB connectivity issues causing a zero count (error swallowed).

Related errors


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