AlistGo/alist · error
[doubao_new] finish upload missing upload_id
Error message
[doubao_new] finish upload missing upload_id
What it means
finishUpload finalizes a completed upload session via POST /space/api/box/upload/finish/ and first validates that uploadID is non-empty. An empty identifier means finalize was attempted without a successful prepare, so the server would have no session to finish.
Source
Thrown at drivers/doubao_new/util.go:876
values.Set("mount_point", "explorer")
values.Set("doubao_storage", "imagex_other")
values.Set("doubao_app_id", "497858")
urlStr := "https://internal-api-drive-stream.feishu.cn/space/api/box/stream/upload/v3/block/?" + values.Encode()
res, err := req.Execute(http.MethodPost, urlStr)
if err != nil {
return err
}
body := res.Body()
if err := decodeBaseResp(body, res); err != nil {
return err
}
return nil
}
func (d *DoubaoNew) finishUpload(ctx context.Context, uploadID string, numBlocks int, mountPoint string) (UploadFinishData, error) {
if uploadID == "" {
return UploadFinishData{}, fmt.Errorf("[doubao_new] finish upload missing upload_id")
}
if numBlocks <= 0 {
return UploadFinishData{}, fmt.Errorf("[doubao_new] finish upload invalid num_blocks")
}
if mountPoint == "" {
mountPoint = "explorer"
}
var resp UploadFinishResp
_, err := d.request(ctx, "/space/api/box/upload/finish/", http.MethodPost, func(req *resty.Request) {
values := url.Values{}
values.Set("shouldBypassScsDialog", "true")
values.Set("doubao_storage", "imagex_other")
values.Set("doubao_app_id", "497858")
req.SetQueryParamsFromValues(values)
req.SetHeader("Content-Type", "application/json")
req.SetHeader("x-command", "space.api.box.upload.finish")
req.SetHeader("rpc-persist-doubao-pan", "true")
req.SetHeader("cache-control", "no-cache")View on GitHub (pinned to 843d9dc814)
Solutions
- Check the prepare result immediately after it returns and abort the upload if UploadID is empty.
- Ensure error paths short-circuit (return on first error) so finish is never reached with partial state.
- Log the full prepare response once to confirm which field carries the upload_id.
Example fix
// before
prep, _ := d.prepareUpload(ctx, ...)
data, err := d.finishUpload(ctx, prep.UploadID, n, "explorer")
// after
prep, err := d.prepareUpload(ctx, ...)
if err != nil { return UploadFinishData{}, err }
if prep.UploadID == "" { return UploadFinishData{}, fmt.Errorf("[doubao_new] prepare returned empty upload_id") }
data, err := d.finishUpload(ctx, prep.UploadID, n, "explorer") Defensive patterns
Strategy: validation
Validate before calling
prep, err := d.prepareUpload(ctx, ...)
if err != nil { return err }
if prep.UploadID == "" { return fmt.Errorf("prepare returned empty upload_id") } Prevention
- Short-circuit on the first error in the upload chain so finish is never reached with partial state.
- Validate prepare output before block upload begins.
When it happens
Trigger: Calling finishUpload after prepare failed or returned an empty UploadID; state lost between prepare and finish (variable shadowing, early error swallowed); direct invocation with "".
Common situations: Error-handling paths that continue to finish even when prepare errored; API schema change emptying the UploadID field; refactors that rename the variable and pass the wrong one.
Related errors
- [doubao_new] merge blocks invalid block origin size
- [doubao_new] merge blocks empty data
- [doubao_new] v3 fallback invalid size: seq=%d size=%d
- [doubao_new] upload v3 block missing upload_id
- [doubao_new] upload v3 block invalid seq
AI-assisted analysis of AlistGo/alist@843d9dc814 (2026-08-15).
Data as JSON: /api/errors/8b1fb8e44e723d69.
Report an issue: GitHub.