{"record":{"id":"f2f321e7b48c059d","repo":"cloudreve/cloudreve","slug":"send-request-failed-w","errorCode":null,"errorMessage":"send request failed: %w","messagePattern":"send request failed: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/downloader/qbittorrent/qbittorrent.go","lineNumber":370,"sourceCode":"\t\treturn fmt.Errorf(\"login failed with response: %s, possibly inccorrect credential is provided\", res)\n\t}\n\n\treturn nil\n}\n\nfunc (c *qbittorrentClient) request(ctx context.Context, method, path string, body string, headers *http.Header) (string, error) {\n\topts := []request.Option{\n\t\trequest.WithContext(ctx),\n\t}\n\n\tif headers != nil {\n\t\topts = append(opts, request.WithHeader(*headers))\n\t}\n\n\tres := c.c.Request(method, path, strings.NewReader(body), opts...)\n\n\tif res.Err != nil {\n\t\treturn \"\", fmt.Errorf(\"send request failed: %w\", res.Err)\n\t}\n\n\tswitch res.Response.StatusCode {\n\tcase http.StatusForbidden:\n\t\tc.l.Info(\"QBittorrent cookie expired, sending login request...\")\n\t\tif err := c.login(ctx); err != nil {\n\t\t\treturn \"\", fmt.Errorf(\"login failed: %w\", err)\n\t\t}\n\n\t\treturn c.request(ctx, method, path, body, headers)\n\n\tcase http.StatusOK:\n\t\trespContent, err := res.GetResponse()\n\t\tif err != nil {\n\t\t\treturn \"\", fmt.Errorf(\"failed reading response: %w\", err)\n\t\t}\n\n\t\treturn respContent, nil","sourceCodeStart":352,"sourceCodeEnd":388,"githubUrl":"https://github.com/cloudreve/cloudreve/blob/20c95ad73f3a8bcb72887fea91ff31ab24fa1011/pkg/downloader/qbittorrent/qbittorrent.go#L352-L388","documentation":"The request client set res.Err before an HTTP status existed - a transport-level failure: DNS resolution failure, connection refused, TLS handshake error, dial/read timeout, or a canceled context. Every qbittorrentClient call (Info, CreateTask, Cancel, Test, setFilePriority) funnels through this wrapper.","triggerScenarios":"Any of those calls while the qBittorrent server is unreachable, the TLS certificate is invalid for https URLs, the port is wrong, a deadline expires, or the passed context is canceled mid-request.","commonSituations":"qBittorrent service down or restarting; firewall blocking the port; self-signed cert without trust; Cloudreve shutting down and canceling in-flight contexts; transient DNS hiccups in container environments.","solutions":["Verify host:port reachability from the Cloudreve machine (curl or nc)","Fix the scheme (http vs https) and port in the node settings","For TLS failures, use a valid certificate or switch to plain http on a trusted network","For context-canceled errors, review the caller's timeout/deadline budget"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// Cheap reachability probe before long operations\nconn, err := net.DialTimeout(\"tcp\", hostPort(cfg.Server), 3*time.Second)\nif err != nil {\n    return fmt.Errorf(\"qbittorrent unreachable: %w\", err)\n}\nconn.Close()","typeGuard":"func isTransportError(err error) bool {\n    return err != nil && strings.Contains(err.Error(), \"send request failed\")\n}","tryCatchPattern":"res, err := op(ctx)\nif isTransportError(err) && !errors.Is(err, context.Canceled) {\n    time.Sleep(backoff)\n    res, err = op(ctx) // one bounded retry on a fresh connection\n}\nif err != nil {\n    return err\n}","preventionTips":["Set sane request timeouts instead of relying on defaults","Monitor qBittorrent service availability from the Cloudreve host","Use stable DNS or IP for the qBittorrent endpoint in container setups"],"tags":["qbittorrent","network","transport","timeout","go"],"backgroundTag":null,"analyzedSha":"20c95ad73f3a8bcb72887fea91ff31ab24fa1011","analyzedAt":"2026-08-16T01:42:55.403Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}