{"record":{"id":"3cdecafd816b2ddd","repo":"AlistGo/alist","slug":"create-offline-task-failed-empty-task-id","errorCode":null,"errorMessage":"create offline task failed: empty task id","messagePattern":"create offline task failed: empty task id","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"drivers/guangyapan/offline.go","lineNumber":77,"sourceCode":"\tbody := map[string]any{\n\t\t\"url\":      taskURL,\n\t\t\"parentId\": parentID,\n\t\t\"newName\":  name,\n\t}\n\tif indexes := resolved.fileIndexes(); len(indexes) > 0 {\n\t\tbody[\"fileIndexes\"] = indexes\n\t}\n\n\tvar resp offlineCreateResp\n\tif err := d.postAPI(ctx, \"/cloudcollection/v1/create_task\", body, &resp); err != nil {\n\t\treturn nil, err\n\t}\n\tif !isSuccessMsg(resp.Msg) {\n\t\treturn nil, fmt.Errorf(\"create offline task failed: %s\", strings.TrimSpace(resp.Msg))\n\t}\n\ttaskID := strings.TrimSpace(resp.Data.TaskID)\n\tif taskID == \"\" {\n\t\treturn nil, errors.New(\"create offline task failed: empty task id\")\n\t}\n\treturn &OfflineTask{\n\t\tTaskID:   taskID,\n\t\tFileName: name,\n\t\tRes:      taskURL,\n\t}, nil\n}\n\nfunc (d *GuangYaPan) OfflineList(ctx context.Context, taskIDs []string, statuses []int, cursor string, pageSize int) ([]OfflineTask, error) {\n\tif err := d.ensureAccessToken(ctx); err != nil {\n\t\treturn nil, err\n\t}\n\tbody := map[string]any{}\n\tif len(taskIDs) > 0 {\n\t\tbody[\"taskIds\"] = taskIDs\n\t}\n\tif len(statuses) > 0 {\n\t\tbody[\"status\"] = statuses","sourceCodeStart":59,"sourceCodeEnd":95,"githubUrl":"https://github.com/AlistGo/alist/blob/843d9dc8149126976b2625911e45a4d3ffd6f2f5/drivers/guangyapan/offline.go#L59-L95","documentation":"After POST /cloudcollection/v1/create_task answered with a success message, resp.Data.TaskID trimmed to empty. The offline task was not actually created server-side (or the response lost the id), so the driver refuses to return a phantom OfflineTask that later polling (OfflineList by task id) could never find.","triggerScenarios":"create_task replies success-shaped JSON with data.taskId absent/blank — e.g. malformed magnet/ed2k URL the backend 'accepted' but did not enqueue, response schema drift, or a proxy stripping the data object.","commonSituations":"User pasted an unsupported or corrupted offline URL; provider changed taskId field name; account offline-task quota exhausted returns success body without a task.","solutions":["Log the full create_task response (code + body) to see why taskId is missing","Validate/normalize the URL via ResolveOfflineResource first and surface its error instead","Check the account's offline-task quota in the GuangYaPan web UI","If the field was renamed server-side, update offlineCreateResp in types.go"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"resolve, err := d.ResolveOfflineResource(ctx, taskURL)\nif err != nil { return nil, err } // reject bad URLs before create_task\nif strings.TrimSpace(resolve.TaskID) == \"\" && strings.TrimSpace(resolve.Name) == \"\" {\n\treturn nil, errors.New(\"offline resource could not be resolved; refusing to create task\")\n}","typeGuard":null,"tryCatchPattern":"task, err := d.createOfflineTask(ctx, ...)\nif err != nil && strings.Contains(err.Error(), \"empty task id\") {\n\treturn nil, fmt.Errorf(\"provider did not accept the offline URL: %w\", err)\n}","preventionTips":["Always resolve the URL before creating the task so user-facing errors come from the resolver","Log create_task code+body when taskId is empty to catch quota/schema issues fast"],"tags":["guangyapan","offline-download","api-contract","driver"],"backgroundTag":null,"analyzedSha":"843d9dc8149126976b2625911e45a4d3ffd6f2f5","analyzedAt":"2026-08-15T12:14:11.722Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}