AlistGo/alist · error

upload part failed: crc32 mismatch, expected %s, got %s

Error message

upload part failed: crc32 mismatch, expected %s, got %s

What it means

Integrity check failure in uploadPart: the client computed CRC32 of the part data before sending, but the server's response envelope reports a different Crc32. The stored bytes do not match what was read, indicating corruption or tampering in transit, or a server-side recalculation mismatch.

Source

Thrown at drivers/doubao/util.go:713

		req.SetQueryParams(map[string]string{
			"uploadid":    uploadID,
			"part_number": strconv.FormatInt(partNumber, 10),
			"phase":       "transfer",
		})

		req.SetBody(data)
		req.SetContentLength(true)
	}, &uploadResp)

	if err != nil {
		return resp, err
	}

	if uploadResp.Code != 2000 {
		return resp, fmt.Errorf("upload part failed: %s", uploadResp.Message)
	} else if uploadResp.Data.Crc32 != crc32Value {
		return resp, fmt.Errorf("upload part failed: crc32 mismatch, expected %s, got %s", crc32Value, uploadResp.Data.Crc32)
	}

	return uploadResp.Data, nil
}

// 完成分片上传
func (d *Doubao) completeMultipartUpload(config *UploadConfig, uploadUrl, uploadID string, parts []UploadPart) error {
	uploadResp := UploadResp{}

	storeInfo := config.InnerUploadAddress.UploadNodes[0].StoreInfos[0]

	body := _convertUploadParts(parts)

	err := utils.Retry(MaxRetryAttempts, time.Second, func() (err error) {
		_, err = d.uploadRequest(uploadUrl, http.MethodPost, storeInfo, func(req *resty.Request) {
			req.SetQueryParams(map[string]string{
				"uploadid":   uploadID,
				"phase":      "finish",

View on GitHub (pinned to 843d9dc814)

Solutions

  1. Retry the part — transient corruption will pass on a clean connection (retry keeps the same CRC so genuine corruption keeps failing)
  2. Disable/inspect any HTTP proxy between OpenList and the upload host
  3. If reproducible on one specific part index, suspect offset arithmetic or buffer reuse in the driver; verify the bytes read at that offset
  4. Check memory/hardware stability if corruption is widespread and random
  5. Compare expected vs got CRC values: a mismatch on the LAST part may point to wrong final-chunk sizing
Defensive patterns

Strategy: retry

Try / catch

if err := d.uploadPart(...); err != nil {
    if strings.Contains(err.Error(), "crc32 mismatch") {
        // re-read the part from disk (fresh bytes) and retry once before failing
        data = rereadPart(offset, size)
        return d.uploadPart(...)
    }
    return err
}

Prevention

When it happens

Trigger: A part POST where the body got altered/corrupted en route (proxy mangling, connection truncation with a 'successful' status), server computed CRC over different bytes (offset mismatch in the chunking logic), or extremely rarely a hash collision-free bug where part data was mutated between calculateCRC32 and send (shared buffer reuse across goroutines).

Common situations: Corporate proxies or MITM devices rewriting bodies, flaky NIC/NAT corrupting large POSTs, race conditions when the part buffer is reused by concurrent goroutines before send completes, or chunk-offset arithmetic bugs after driver changes.

Related errors


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