{"record":{"id":"b9c9d7474262ea31","repo":"AlistGo/alist","slug":"doubao-new-merge-blocks-invalid-block-origin-siz","errorCode":null,"errorMessage":"[doubao_new] merge blocks invalid block origin size","messagePattern":"\\[doubao_new\\] merge blocks invalid block origin size","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"drivers/doubao_new/util.go","lineNumber":709,"sourceCode":"\t}\n\treturn resp.Data, nil\n}\n\nfunc (d *DoubaoNew) mergeUploadBlocks(ctx context.Context, uploadID string, seqList []int, checksumList []string, sizeList []int64, blockOriginSize int64, data []byte) (UploadMergeData, error) {\n\tif uploadID == \"\" {\n\t\treturn UploadMergeData{}, fmt.Errorf(\"[doubao_new] merge blocks missing upload_id\")\n\t}\n\tif len(seqList) == 0 {\n\t\treturn UploadMergeData{}, fmt.Errorf(\"[doubao_new] merge blocks empty seq list\")\n\t}\n\tif len(checksumList) == 0 {\n\t\treturn UploadMergeData{}, fmt.Errorf(\"[doubao_new] merge blocks empty checksum list\")\n\t}\n\tif len(sizeList) != len(seqList) {\n\t\treturn UploadMergeData{}, fmt.Errorf(\"[doubao_new] merge blocks size list mismatch\")\n\t}\n\tif blockOriginSize <= 0 {\n\t\treturn UploadMergeData{}, fmt.Errorf(\"[doubao_new] merge blocks invalid block origin size\")\n\t}\n\tif len(data) == 0 {\n\t\treturn UploadMergeData{}, fmt.Errorf(\"[doubao_new] merge blocks empty data\")\n\t}\n\n\tseqHeader := joinIntComma(seqList)\n\tchecksumHeader := buildCommaHeader(checksumList)\n\n\tclient := base.NewRestyClient()\n\tclient.SetCookieJar(nil)\n\treq := client.R()\n\treq.SetContext(ctx)\n\treq.SetHeader(\"accept\", \"application/json, text/plain, */*\")\n\treq.SetHeader(\"origin\", \"https://www.doubao.com\")\n\treq.SetHeader(\"referer\", \"https://www.doubao.com/\")\n\treq.SetHeader(\"user-agent\", \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36\")\n\treq.SetHeader(\"rpc-persist-doubao-pan\", \"true\")\n\treq.SetHeader(\"content-type\", \"application/octet-stream\")","sourceCodeStart":691,"sourceCodeEnd":727,"githubUrl":"https://github.com/AlistGo/alist/blob/843d9dc8149126976b2625911e45a4d3ffd6f2f5/drivers/doubao_new/util.go#L691-L727","documentation":"mergeUploadBlocks validates its arguments before POSTing the merge_block request to internal-api-drive-stream.feishu.cn. blockOriginSize is the fixed block size the server told the client to use (sent as the x-block-origin-size header, util.go:730) and the caller passes the blockSize obtained from the upload-prepare response (driver.go:311). A value <= 0 means the prepare step returned no usable block size, so the merge request could not be built.","triggerScenarios":"Calling mergeUploadBlocks when the upload-prepare API returned BlockSize/BlockOriginSize of 0 or a negative value (empty field, changed response schema, or API change), or a custom caller passing a hardcoded 0. Triggered on any Put of a file large enough to need >= 1 block upload.","commonSituations":"Doubao/Feishu internal API changed its prepare response shape so the block-size field no longer unmarshals; uploading an empty or very small file whose prepare returns no block size; a driver update that renames the JSON field and silently leaves blockSize zero.","solutions":["Inspect the upload-prepare response (decode and log it) and confirm which JSON field carries the block size; fix the struct tag in types.go if the field name changed.","Guard the prepare result before uploading: fail fast with a clear error if UploadPrep.BlockSize <= 0 instead of propagating it into mergeUploadBlocks.","If the file is empty (size 0), skip the block-upload/merge path entirely and use the direct/finish upload path.","Retry with a fresh login/token: an expired or downgraded session can make prepare return a partial payload with code 0 but no data."],"exampleFix":"// before\nmergeResp, err := d.mergeUploadBlocks(ctx, uploadPrep.UploadID, groupSeqs, groupChecksums, groupSizes, blockSize, data)\n\n// after\nif blockSize <= 0 {\n    return nil, fmt.Errorf(\"[doubao_new] upload prepare returned invalid block size: %d\", blockSize)\n}\nmergeResp, err := d.mergeUploadBlocks(ctx, uploadPrep.UploadID, groupSeqs, groupChecksums, groupSizes, blockSize, data)","handlingStrategy":"validation","validationCode":"// before uploading, verify the prepare result is usable\nif uploadPrep.UploadID == \"\" || uploadPrep.BlockSize <= 0 {\n    return fmt.Errorf(\"[doubao_new] upload prepare unusable: upload_id=%q block_size=%d\", uploadPrep.UploadID, uploadPrep.BlockSize)\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Validate prepare responses (upload_id present, block size > 0) immediately, before any block work.","Route zero-byte files around the chunked path.","Log the raw prepare response once when schema changes are suspected."],"tags":["doubao","upload","validation","multipart"],"backgroundTag":null,"analyzedSha":"843d9dc8149126976b2625911e45a4d3ffd6f2f5","analyzedAt":"2026-08-15T12:14:11.722Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}