flipped-aurora/gin-vue-admin · error

缺少分片 %d: %w

Error message

缺少分片 %d: %w

What it means

MergeChunks reassembles uploaded chunk files (<i>.part) under ChunkDir(uploadID) into the final file while computing MD5. If any expected chunk file cannot be opened, it aborts with "缺少分片 %d: %w". This guards against incomplete uploads being merged into corrupt files.

Source

Thrown at server/utils/upload/chunk.go:59

}

// MergeChunks 按 0..total-1 顺序流式合并到 dstPath,返回成品 md5
func MergeChunks(uploadID uint, total int, dstPath string) (string, error) {
	if err := os.MkdirAll(filepath.Dir(dstPath), os.ModePerm); err != nil {
		return "", err
	}
	out, err := os.Create(dstPath)
	if err != nil {
		return "", err
	}
	defer out.Close()
	h := md5.New()
	w := io.MultiWriter(out, h)
	for i := 0; i < total; i++ {
		p := filepath.Join(ChunkDir(uploadID), fmt.Sprintf("%d.part", i))
		in, err := os.Open(p)
		if err != nil {
			return "", fmt.Errorf("缺少分片 %d: %w", i, err)
		}
		if _, err := io.Copy(w, in); err != nil {
			in.Close()
			return "", err
		}
		in.Close()
	}
	return hex.EncodeToString(h.Sum(nil)), nil
}

// RemoveUploadDir 删除某次上传的暂存目录
func RemoveUploadDir(uploadID uint) error {
	return os.RemoveAll(ChunkDir(uploadID))
}

// ReceivedIndexes 扫描暂存目录已存在的分片索引(机会式恢复用,可选)
func ReceivedIndexes(uploadID uint) []int {
	entries, err := os.ReadDir(ChunkDir(uploadID))

View on GitHub (pinned to 3136500ef3)

Solutions

  1. Re-upload the missing chunk(s) reported by the error index before calling MergeChunks.
  2. Verify the client sends every chunk index 0..total-1 and confirm chunk completeness server-side before merging.
  3. Check ChunkDir(uploadID) for the expected .part files (ls the directory) to find which are missing.
  4. If chunks were cleaned up, restart the whole chunked upload with a new uploadID.

Example fix

// before
merged, _ := MergeChunks(id, 5, dest) // chunk 3 never uploaded

// after
for i := 0; i < 5; i++ {
    if _, err := os.Stat(filepath.Join(ChunkDir(id), fmt.Sprintf("%d.part", i))); err != nil {
        uploadChunk(id, i, data[i]) // re-send missing chunk
    }
}
merged, err := MergeChunks(id, 5, dest)
Defensive patterns

Strategy: validation

Validate before calling

func chunksComplete(uploadID string, total int) error {
    for i := 0; i < total; i++ {
        p := filepath.Join(ChunkDir(uploadID), fmt.Sprintf("%d.part", i))
        if _, err := os.Stat(p); err != nil {
            return fmt.Errorf("chunk %d missing", i)
        }
    }
    return nil
}

Try / catch

if err := chunksComplete(id, total); err != nil {
    return retryMissingChunks(id, err) // re-upload missing parts before merge
}
md5, err := upload.MergeChunks(id, total, dest)
if err != nil {
    return fmt.Errorf("merge aborted: %w", err)
}

Prevention

When it happens

Trigger: Calling MergeChunks(uploadID, total, ...) when one or more files ChunkDir(uploadID)/i.part for i in [0,total) do not exist (os.Open fails) — typically because an earlier chunk upload failed or was never sent.

Common situations: Client aborted mid-upload and the UI still requested merge; network drop caused chunk 3 of 10 to fail; chunk index numbering mismatch (client sends 1-based, server expects 0-based); cleanup job removed partial chunk dirs.

Related errors


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