AlistGo/alist · error
wukong multipart finish failed: code=%d message=%s
Error message
wukong multipart finish failed: code=%d message=%s
What it means
Thrown by finishMultipartUpload when the phase=finish POST returns a code that is neither 2000 (success) nor 4024 (tolerated — typically 'already finished/duplicate'). Finishing stitches the uploaded parts into the final object; failure here wastes the whole multipart session.
Source
Thrown at drivers/wukong/driver.go:722
SetHeader("Origin", "https://pan.wkbrowser.com").
SetHeader("Authorization", auth).
SetQueryParams(map[string]string{
"uploadid": uploadID,
"phase": "finish",
"uploadmode": "part",
}).
SetBody(body).
SetResult(&resp)
if storageUser != "" {
req.SetHeader("X-Storage-U", storageUser)
}
uploadURL := fmt.Sprintf("https://%s/upload/v1/%s", host, storeURI)
_, err := req.Post(uploadURL)
if err != nil {
return err
}
if resp.Code != minUploadSubmitSuccess && resp.Code != 4024 {
return fmt.Errorf("wukong multipart finish failed: code=%d message=%s", resp.Code, resp.Message)
}
return nil
}
func (d *Wukong) vodRequest(ctx context.Context, method string, query map[string]string, body []byte, auth *uploadAuthTokenResp, resp any) error {
reqURL := vodBaseURL + "/"
amzDate := time.Now().UTC().Format("20060102T150405Z")
dateStamp := amzDate[:8]
headers := map[string]string{
"x-amz-date": amzDate,
"x-amz-security-token": auth.SessionToken,
}
if method == http.MethodPost {
headers["x-amz-content-sha256"] = hashSHA256Bytes(body)
}
authorization := buildVodAuthorization(method, "/", query, headers, body, auth, dateStamp)
req := base.NewRestyClient().R().View on GitHub (pinned to 843d9dc814)
Solutions
- Only call finish after every part uploaded successfully and its CRC matched (parts slice complete)
- Retry finish once — transient assembly errors are common for huge objects
- If the code suggests the session was already finished, proceed to uploadSubmit instead of erroring (mirror the 4024 tolerance)
- Re-mint auth token before finish for long-running multipart uploads
Defensive patterns
Strategy: retry
Try / catch
if err := d.finishMultipartUpload(ctx, host, storeURI, auth, storageUser, uploadID, partsBody); err != nil {
if isWukongTOSCode(err, 4024) {
return nil // already finished (driver already tolerates, keep for safety)
}
time.Sleep(2 * time.Second)
return d.finishMultipartUpload(ctx, host, storeURI, auth, storageUser, uploadID, partsBody)
} Prevention
- Only finish when len(parts) == totalParts and every CRC matched
- Keep the parts list body strictly 'num:crc' comma-joined with ascending part numbers
- Mint a fresh token before finish on long uploads
When it happens
Trigger: Part list body ("num:crc" joined string) malformed or referencing a missing part; auth expired by the time the last part finished; uploadID already aborted; upstream error assembling parts.
Common situations: A part failed earlier and the code path still attempted finish; very large files where finish exceeds token TTL; retrying finish after a timeout that actually succeeded server-side (hence 4024 tolerance).
Related errors
- wukong init multipart upload failed: code=%d message=%s
- wukong multipart transfer failed: code=%d message=%s part=%d
- wukong init multipart upload returns empty uploadid
- finish upload failed: %s
- wukong upload to tos failed: code=%d message=%s
AI-assisted analysis of AlistGo/alist@843d9dc814 (2026-08-15).
Data as JSON: /api/errors/6941cfc2531bb02f.
Report an issue: GitHub.