{"record":{"id":"c3b1e500a3aa16ca","repo":"AlistGo/alist","slug":"failed-to-add-offline-download-task-w-c3b1e5","errorCode":null,"errorMessage":"failed to add offline download task: %w","messagePattern":"failed to add offline download task: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/offline_download/pikpak/pikpak.go","lineNumber":78,"sourceCode":"\tpikpakDriver, ok := storage.(*pikpak.PikPak)\n\tif !ok {\n\t\treturn \"\", fmt.Errorf(\"unsupported storage driver for offline download, only Pikpak is supported\")\n\t}\n\n\tctx := context.Background()\n\n\tif err := op.MakeDir(ctx, storage, actualPath); err != nil {\n\t\treturn \"\", err\n\t}\n\n\tparentDir, err := op.GetUnwrap(ctx, storage, actualPath)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tt, err := pikpakDriver.OfflineDownload(ctx, args.Url, parentDir, \"\")\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"failed to add offline download task: %w\", err)\n\t}\n\n\treturn t.ID, nil\n}\n\nfunc (p *PikPak) Remove(task *tool.DownloadTask) error {\n\tstorage, _, err := op.GetStorageAndActualPath(task.TempDir)\n\tif err != nil {\n\t\treturn err\n\t}\n\tpikpakDriver, ok := storage.(*pikpak.PikPak)\n\tif !ok {\n\t\treturn fmt.Errorf(\"unsupported storage driver for offline download, only Pikpak is supported\")\n\t}\n\tctx := context.Background()\n\terr = pikpakDriver.DeleteOfflineTasks(ctx, []string{task.GID}, false)\n\tif err != nil {\n\t\treturn err","sourceCodeStart":60,"sourceCodeEnd":96,"githubUrl":"https://github.com/AlistGo/alist/blob/843d9dc8149126976b2625911e45a4d3ffd6f2f5/internal/offline_download/pikpak/pikpak.go#L60-L96","documentation":"PikPak.AddURL() wraps any failure of pikpakDriver.OfflineDownload() with 'failed to add offline download task'. The underlying cause rides in the %w chain: expired PikPak token, magnet/URL rejected by the platform, vip-only resource restrictions, or API errors.","triggerScenarios":"Submitting a URL or magnet with tool=pikpak after the stored PikPak credentials expired, when the platform refuses the link (copyright/vip restriction), or when the parent directory lookup produced an invalid target.","commonSituations":"Long-running deployments whose PikPak login token lapsed; sharing links that require a paid PikPak plan; adding many tasks rapidly and hitting API rate limits.","solutions":["Inspect the wrapped error message for the platform's own failure reason","Refresh PikPak credentials on the storage and retry the add","Test the same link in the PikPak app to confirm it is accepted for your account tier","Retry with backoff if the wrapped error is a rate/limit message"],"exampleFix":"t, err := pikpakDriver.OfflineDownload(ctx, args.Url, parentDir, \"\")\nif err != nil {\n    return \"\", fmt.Errorf(\"failed to add offline download task: %w\", err)\n}\n\n// caller-side: single retry after re-auth on auth errors\nif strings.Contains(err.Error(), \"token\") {\n    refreshPikPakToken(storage)\n    t, err = pikpakDriver.OfflineDownload(ctx, args.Url, parentDir, \"\")\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"id, err := p.AddURL(args)\nif err != nil {\n    if strings.Contains(err.Error(), \"failed to add offline download task\") {\n        cause := errors.Unwrap(err)\n        if isTokenError(cause) {\n            return retryAfterReauth(args) // single controlled retry\n        }\n        return fmt.Errorf(\"pikpak refused task: %v\", cause)\n    }\n    return err\n}","preventionTips":["Refresh PikPak tokens proactively on a schedule shorter than their lifetime","Distinguish auth vs quota vs link errors from the wrapped cause before retrying","Never blind-retry in a tight loop; rate limits make it worse"],"tags":["pikpak","offline-download","auth","error-wrapping"],"backgroundTag":null,"analyzedSha":"843d9dc8149126976b2625911e45a4d3ffd6f2f5","analyzedAt":"2026-08-15T12:14:11.722Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}