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

  1. Retry the failed part (same uploadID and partNumber) with backoff — most part failures are transient
  2. If the code indicates auth expiry, restart from applyUploadInner for a fresh session
  3. Ensure only one writer uses a given uploadID/storeURI at a time
  4. 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

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


AI-assisted analysis of AlistGo/alist@843d9dc814 (2026-08-15). Data as JSON: /api/errors/a29925891234a364. Report an issue: GitHub.