{"record":{"id":"e83cad33b94c6cab","repo":"AlistGo/alist","slug":"failed-to-parse-task-id-w","errorCode":null,"errorMessage":"failed to parse task id: %w","messagePattern":"failed to parse task id: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"drivers/sjtu_netdisk/driver.go","lineNumber":549,"sourceCode":"\n\t\t\treturn &model.Object{\n\t\t\t\tName:     srcObj.GetName(),\n\t\t\t\tSize:     srcObj.GetSize(),\n\t\t\t\tIsFolder: true,\n\t\t\t\tModified: srcObj.ModTime(),\n\t\t\t\tCtime:    time.Now(),\n\t\t\t\tPath:     targetPath,\n\t\t\t}, nil\n\t\t}\n\n\t\t// 202 Accepted：polling task status\n\t\tif resp.StatusCode() != http.StatusAccepted {\n\t\t\treturn nil, fmt.Errorf(\"unexpected copy folder response: status=%d\", resp.StatusCode())\n\t\t}\n\n\t\tvar taskResp TaskInitResp\n\t\tif err := json.Unmarshal(resp.Body(), &taskResp); err != nil || taskResp.TaskId == 0 {\n\t\t\treturn nil, fmt.Errorf(\"failed to parse task id: %w\", err)\n\t\t}\n\n\t\ttaskURL := fmt.Sprintf(\"%s/task/%s/%s/%d\", API_URL, d.libraryId, d.spaceId, taskResp.TaskId)\n\t\tactualName := srcObj.GetName()\n\t\ttaskDone := false\n\n\t\tfor i := 0; i < 30 && !taskDone; i++ {\n\t\t\tselect {\n\t\t\tcase <-ctx.Done():\n\t\t\t\treturn nil, ctx.Err()\n\t\t\tcase <-time.After(1 * time.Second):\n\t\t\t}\n\n\t\t\tvar taskStatus []TaskStatusItem\n\t\t\t_, pollErr := d.newClient().R().\n\t\t\t\tSetContext(ctx).\n\t\t\t\tSetQueryParam(\"access_token\", d.accessToken).\n\t\t\t\tSetResult(&taskStatus).","sourceCodeStart":531,"sourceCodeEnd":567,"githubUrl":"https://github.com/AlistGo/alist/blob/843d9dc8149126976b2625911e45a4d3ffd6f2f5/drivers/sjtu_netdisk/driver.go#L531-L567","documentation":"After a 202 response to a folder copy, the SJTU driver parses the body as a task-init response ({task_id}). This error fires when JSON unmarshal fails OR the parsed TaskId is 0. Note the bug: when TaskId==0 but unmarshal succeeded, err is nil, so the message renders '%!w(<nil>)' and the real cause is the zero/missing task_id field.","triggerScenarios":"Server returns 202 with an empty or differently-shaped body (e.g. an error page from a proxy), or a JSON without a usable task_id field; also any body where task_id is absent/0.","commonSituations":"Reverse proxy intercepting the 202 and rewriting the body; API version change renaming the task id field; server acknowledging but failing to schedule the task.","solutions":["Retry the copy — transient 202-with-bad-body responses occur under server load","Inspect the raw response body (log it) to see what the server actually returned","If a proxy is involved, bypass it or fix its response handling","If the field name changed upstream, update TaskInitResp's json tag in the driver","Fix the driver to distinguish unmarshal failure from zero task id and include the body in the error"],"exampleFix":"// before\nif err := json.Unmarshal(resp.Body(), &taskResp); err != nil || taskResp.TaskId == 0 {\n    return nil, fmt.Errorf(\"failed to parse task id: %w\", err)\n}\n// after\nif err := json.Unmarshal(resp.Body(), &taskResp); err != nil {\n    return nil, fmt.Errorf(\"failed to parse task id: %w, body: %s\", err, resp.String())\n}\nif taskResp.TaskId == 0 {\n    return nil, fmt.Errorf(\"task id missing in response body: %s\", resp.String())\n}","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"if err != nil && strings.Contains(err.Error(), \"failed to parse task id\") {\n    // body was empty/reshaped or task_id was 0; a fresh copy gets a new task\n    return retryFolderCopyOnce()\n}","preventionTips":["Note '%!w(<nil>)' in the message means task_id was 0, not a JSON error — inspect the body","Retry once; transient malformed 202 bodies occur under load","Keep proxies from rewriting 202 response bodies"],"tags":["sjtu-netdisk","json","parsing","async-task","bug"],"backgroundTag":null,"analyzedSha":"843d9dc8149126976b2625911e45a4d3ffd6f2f5","analyzedAt":"2026-08-15T12:14:11.722Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}