{"record":{"id":"03739483753b5dc9","repo":"AlistGo/alist","slug":"failed-to-add-qbittorrent-task-link","errorCode":null,"errorMessage":"failed to add qBittorrent task: {link}","messagePattern":"failed to add qBittorrent task: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/qbittorrent/client.go","lineNumber":168,"sourceCode":"\treq, err := http.NewRequest(\"POST\", u.String(), buf)\n\tif err != nil {\n\t\treturn err\n\t}\n\treq.Header.Add(\"Content-Type\", writer.FormDataContentType())\n\n\tresp, err := c.client.Do(req)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// check result\n\tbody := make([]byte, 2)\n\t_, err = resp.Body.Read(body)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif resp.StatusCode != 200 || string(body) != \"Ok\" {\n\t\treturn errors.New(\"failed to add qBittorrent task: \" + link)\n\t}\n\treturn nil\n}\n\ntype TorrentStatus string\n\nconst (\n\tERROR              TorrentStatus = \"error\"\n\tMISSINGFILES       TorrentStatus = \"missingFiles\"\n\tUPLOADING          TorrentStatus = \"uploading\"\n\tPAUSEDUP           TorrentStatus = \"pausedUP\"\n\tQUEUEDUP           TorrentStatus = \"queuedUP\"\n\tSTALLEDUP          TorrentStatus = \"stalledUP\"\n\tCHECKINGUP         TorrentStatus = \"checkingUP\"\n\tFORCEDUP           TorrentStatus = \"forcedUP\"\n\tALLOCATING         TorrentStatus = \"allocating\"\n\tDOWNLOADING        TorrentStatus = \"downloading\"\n\tMETADL             TorrentStatus = \"metaDL\"","sourceCodeStart":150,"sourceCodeEnd":186,"githubUrl":"https://github.com/AlistGo/alist/blob/843d9dc8149126976b2625911e45a4d3ffd6f2f5/pkg/qbittorrent/client.go#L150-L186","documentation":"Adding a torrent/magnet to qBittorrent via /api/v2/torrents/add failed: the HTTP status was not 200 or the response body was not \"Ok\". The error embeds the submitted link so you can see which one failed.","triggerScenarios":"Calling AddTorrentTask with a malformed magnet URI or .torrent link, an unreachable URL for URL-based downloads, a session that lost authorization, or a full/inaccessible download directory.","commonSituations":"Magnet link truncated or with a bad xt hash; torrent file URL requiring auth; qBittorrent's default save path missing (removed disk); WebUI session cookie expired mid-operation.","solutions":["Validate the magnet URI format (must contain xt=urn:btih:...) or the .torrent URL before submitting","Check the qBittorrent download directory exists and is writable","Re-verify login/authorization (the 403 case) and retry after re-login"],"exampleFix":"// before\nerr := c.AddTorrentTask(\"magnet:?xt=btih:WRONGHASH\", \"\", false)\n\n// after\nmagnet := \"magnet:?xt=urn:btih:<40-char-infohash>&dn=name\"\nerr := c.AddTorrentTask(magnet, \"\", false)","handlingStrategy":"validation","validationCode":"func validMagnet(m string) bool {\n\treturn strings.HasPrefix(m, \"magnet:?\") && strings.Contains(m, \"xt=urn:btih:\")\n}\nif !validMagnet(link) && !strings.HasSuffix(link, \".torrent\") {\n\treturn errors.New(\"not a valid magnet or torrent link\")\n}","typeGuard":null,"tryCatchPattern":"err := c.AddTorrentTask(link, \"\", false)\nif err != nil && strings.Contains(err.Error(), \"failed to add qBittorrent task\") {\n\tlog.Warnf(\"qBittorrent rejected link %q (status/body mismatch)\", link)\n}","preventionTips":["Validate magnet URIs before submission","Ensure the qBittorrent save path exists and is writable"],"tags":["qbittorrent","torrent","magnet","offline-download"],"backgroundTag":null,"analyzedSha":"843d9dc8149126976b2625911e45a4d3ffd6f2f5","analyzedAt":"2026-08-15T12:14:11.722Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}