{"record":{"id":"04147c36d394de9f","repo":"AlistGo/alist","slug":"failed-to-add-offline-download-task-w-04147c","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/thunder/thunder.go","lineNumber":79,"sourceCode":"\tthunderDriver, ok := storage.(*thunder.Thunder)\n\tif !ok {\n\t\treturn \"\", fmt.Errorf(\"unsupported storage driver for offline download, only Thunder 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\ttask, err := thunderDriver.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 task.ID, nil\n}\n\nfunc (t *Thunder) Remove(task *tool.DownloadTask) error {\n\tstorage, _, err := op.GetStorageAndActualPath(task.TempDir)\n\tif err != nil {\n\t\treturn err\n\t}\n\tthunderDriver, ok := storage.(*thunder.Thunder)\n\tif !ok {\n\t\treturn fmt.Errorf(\"unsupported storage driver for offline download, only Thunder is supported\")\n\t}\n\tctx := context.Background()\n\terr = thunderDriver.DeleteOfflineTasks(ctx, []string{task.GID}, false)\n\tif err != nil {\n\t\treturn err","sourceCodeStart":61,"sourceCodeEnd":97,"githubUrl":"https://github.com/AlistGo/alist/blob/843d9dc8149126976b2625911e45a4d3ffd6f2f5/internal/offline_download/thunder/thunder.go#L61-L97","documentation":"Thunder.AddURL() wraps failures of thunderDriver.OfflineDownload() with 'failed to add offline download task'. The wrapped error carries the actual cause: expired Thunder login (captcha/QR re-auth needed), link refused by the platform, or quota limits on the Xunlei account.","triggerScenarios":"Submitting a URL/magnet with tool=thunder when the stored Thunder session expired, when the resource is unavailable to the account, or when the daily offline-task quota is exhausted.","commonSituations":"Thunder sessions expiring every few weeks and requiring re-scan of the QR login; links behind vip restrictions; adding magnet links the platform does not resolve.","solutions":["Unwrap and read the underlying error for the platform's reason","Re-authenticate the Thunder storage (fresh QR login in storage settings) and retry","Verify the link downloads in the official Thunder client for the same account","Wait and retry if the wrapped error reports quota/rate limits"],"exampleFix":"task, err := thunderDriver.OfflineDownload(ctx, args.Url, parentDir, \"\")\nif err != nil {\n    return \"\", fmt.Errorf(\"failed to add offline download task: %w\", err)\n}\n\n// caller: surface the wrapped cause to the user\nif err != nil {\n    log.Warnf(\"thunder add failed: %v\", errors.Unwrap(err))\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"id, err := t.AddURL(args)\nif err != nil {\n    if strings.Contains(err.Error(), \"failed to add offline download task\") {\n        cause := errors.Unwrap(err)\n        if isSessionExpired(cause) {\n            return errorWithHint(cause, \"re-scan QR login for the Thunder storage, then retry\")\n        }\n        return fmt.Errorf(\"thunder refused task: %v\", cause)\n    }\n    return err\n}","preventionTips":["Re-authenticate Thunder storage on a regular cadence; sessions expire","Test links in the official client before queuing them here","Surface the unwrapped platform error to users instead of the generic wrapper"],"tags":["thunder","offline-download","auth","error-wrapping"],"backgroundTag":null,"analyzedSha":"843d9dc8149126976b2625911e45a4d3ffd6f2f5","analyzedAt":"2026-08-15T12:14:11.722Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}