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

  1. Only call finish after every part uploaded successfully and its CRC matched (parts slice complete)
  2. Retry finish once — transient assembly errors are common for huge objects
  3. If the code suggests the session was already finished, proceed to uploadSubmit instead of erroring (mirror the 4024 tolerance)
  4. 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

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


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