AlistGo/alist · error
wukong multipart transfer failed: code=%d message=%s part=%d
Error message
wukong multipart transfer failed: code=%d message=%s part=%d
What it means
Thrown by uploadMultipartPart when POSTing one part's bytes to https://<host>/upload/v1/<storeURI> gets back a code other than 2000. The part transfer failed at the storage layer; the caller (uploadToTOSMultipart) sees this error and aborts the multipart session.
Source
Thrown at drivers/wukong/driver.go:693
SetHeader("Content-Crc32", crc32Hex).
SetHeader("Content-Length", strconv.Itoa(len(data))).
SetQueryParams(map[string]string{
"uploadid": uploadID,
"part_number": strconv.Itoa(partNumber),
"phase": "transfer",
}).
SetBody(data).
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 {
return "", fmt.Errorf("wukong multipart transfer failed: code=%d message=%s part=%d", resp.Code, resp.Message, partNumber)
}
return resp.Data.Crc32, nil
}
func (d *Wukong) finishMultipartUpload(ctx context.Context, host, storeURI, auth, storageUser, uploadID, body string) error {
var resp tosUploadResp
req := base.NewRestyClient().R().
SetContext(ctx).
SetHeader("Host", host).
SetHeader("Referer", webReferer).
SetHeader("Origin", "https://pan.wkbrowser.com").
SetHeader("Authorization", auth).
SetQueryParams(map[string]string{
"uploadid": uploadID,
"phase": "finish",
"uploadmode": "part",
}).
SetBody(body).View on GitHub (pinned to 843d9dc814)
Solutions
- Retry the failed part (same uploadID and partNumber) with backoff — most part failures are transient
- If the code indicates auth expiry, restart from applyUploadInner for a fresh session
- Ensure only one writer uses a given uploadID/storeURI at a time
- Reduce multipartChunkSize if hosts reject large single parts
Defensive patterns
Strategy: retry
Try / catch
remoteCRC32, err := d.uploadMultipartPart(ctx, host, storeURI, auth, storageUser, uploadID, partNumber, buf, crc32Hex)
if err != nil {
if isTransientTOSCode(err) { // 5xx-ish envelope codes
time.Sleep(backoff(partNumber))
remoteCRC32, err = d.uploadMultipartPart(ctx, host, storeURI, auth, storageUser, uploadID, partNumber, buf, crc32Hex)
}
if err != nil { return err }
} Prevention
- Retry individual parts with exponential backoff before failing the session
- Ensure exclusive ownership of an uploadID per client
- Monitor part failure rate; persistent failures indicate token expiry, not flakiness
When it happens
Trigger: Part number out of range or already finalized; auth token expiring mid-multipart; part body too large for the host; transient 5xx mapped into the envelope code; uploadID invalidated by a parallel finish/abort.
Common situations: Long uploads outliving the token; two clients uploading to the same storeURI; network instability during large parts; host throttling after many rapid parts.
Related errors
- wukong init multipart upload failed: code=%d message=%s
- wukong multipart finish failed: code=%d message=%s
- wukong init multipart upload returns empty uploadid
- wukong upload to tos failed: code=%d message=%s
- wukong upload to tos crc32 mismatch: local=%s remote=%s
AI-assisted analysis of AlistGo/alist@843d9dc814 (2026-08-15).
Data as JSON: /api/errors/a29925891234a364.
Report an issue: GitHub.