{"record":{"id":"3ecef89411d3c580","repo":"Sonarr/Sonarr","slug":"remote-website-tried-to-redirect-without-providing","errorCode":null,"errorMessage":"Remote website tried to redirect without providing a location.","messagePattern":"Remote website tried to redirect without providing a location\\.","errorType":"exception","errorClass":"WebException","httpStatus":null,"severity":"error","filePath":"src/NzbDrone.Core/Download/TorrentClientBase.cs","lineNumber":166,"sourceCode":"                    response.StatusCode == HttpStatusCode.SeeOther)\n                {\n                    var locationHeader = response.Headers.GetSingleValue(\"Location\");\n\n                    _logger.Trace(\"Torrent request is being redirected to: {0}\", locationHeader);\n\n                    if (locationHeader != null)\n                    {\n                        if (locationHeader.StartsWith(\"magnet:\"))\n                        {\n                            return DownloadFromMagnetUrl(remoteEpisode, indexer, locationHeader);\n                        }\n\n                        request.Url += new HttpUri(locationHeader);\n\n                        return await DownloadFromWebUrl(remoteEpisode, indexer, request.Url.ToString());\n                    }\n\n                    throw new WebException(\"Remote website tried to redirect without providing a location.\");\n                }\n\n                torrentFile = response.ResponseData;\n\n                _logger.Debug(\"Downloading torrent for episode '{0}' finished ({1} bytes from {2})\", remoteEpisode.Release.Title, torrentFile.Length, torrentUrl);\n            }\n            catch (HttpException ex)\n            {\n                if (ex.Response.StatusCode is HttpStatusCode.NotFound or HttpStatusCode.Gone)\n                {\n                    _logger.Error(ex, \"Downloading torrent file for episode '{0}' failed since it no longer exists ({1})\", remoteEpisode.Release.Title, torrentUrl);\n                    throw new ReleaseUnavailableException(remoteEpisode.Release, \"Downloading torrent failed\", ex);\n                }\n\n                if ((int)ex.Response.StatusCode == 429)\n                {\n                    _logger.Error(\"API Grab Limit reached for {0}\", torrentUrl);\n                }","sourceCodeStart":148,"sourceCodeEnd":184,"githubUrl":"https://github.com/Sonarr/Sonarr/blob/da2284d7eaab22ed9b2ca698af690148d691e967/src/NzbDrone.Core/Download/TorrentClientBase.cs#L148-L184","documentation":"Raised inside DownloadFromWebUrl when the indexer responds with a 3xx redirect (301/302/303) but the Location header is absent or null. Auto-redirect is explicitly disabled (request.AllowAutoRedirect = false) so Sonarr can detect magnet-redirects, and a redirect without a target is treated as a protocol violation. Wrapped later as WebException -> ReleaseDownloadException.","triggerScenarios":"The .torrent URL returns MovedPermanently/Found/SeeOther and the response headers contain no 'Location' value (locationHeader == null at TorrentClientBase.cs:154-166). Happens with misconfigured indexers, reverse proxies that strip the Location header, or server bugs.","commonSituations":"A CDN or reverse proxy (nginx, Cloudflare) rewrites redirect responses and drops the Location header; the indexer endpoint was deprecated and issues an empty redirect; a captive portal redirects without a Location; the server returns a 302 body but the header name casing is unusual and GetSingleValue misses it.","solutions":["Open the .torrent URL in a browser/curl -i and verify a Location header is present on any redirect.","If a reverse proxy/CDN strips Location, fix the proxy config to preserve it.","Update or correct the indexer grab URL so it does not rely on a broken redirect.","Report the empty-redirect bug to the indexer if it reproduces on their endpoint."],"exampleFix":"// before: any missing Location is a hard WebException\nthrow new WebException(\"Remote website tried to redirect without providing a location.\");\n\n// after: tolerate and retry the original URL or surface a clearer error\n_logger.Warn(\"Redirect {0} from {1} had no Location; retrying original URL\",\n    response.StatusCode, torrentUrl);\nthrow new ReleaseDownloadException(remoteEpisode.Release,\n    \"Redirect from indexer missing Location header\", ex);","handlingStrategy":"validation","validationCode":"// Inspect redirect responses for a Location before relying on them\nvar location = response.Headers.GetSingleValue(\"Location\");\nif ((int)response.StatusCode is >= 300 and < 400 && location.IsNullOrWhiteSpace())\n{\n    _logger.Warn(\"Redirect {0} from {1} lacks Location; ignoring redirect\",\n        response.StatusCode, torrentUrl);\n    // fall through to treat response body as the torrent, or retry\n}","typeGuard":"static bool HasUsableRedirect(HttpResponse r)\n    => (int)r.StatusCode is >= 300 and < 400\n       && r.Headers.GetSingleValue(\"Location\").IsNullOrWhiteSpace() == false;","tryCatchPattern":"try { /* fetch torrent */ }\ncatch (WebException ex) when (ex.Message.Contains(\"redirect without providing a location\"))\n{\n    _logger.Warn(\"Indexer returned a Location-less redirect for {0}\", torrentUrl);\n    // mark indexer as degraded, try alternate release\n}","preventionTips":["Do not assume 3xx always carries Location - validate before following.","Ensure reverse proxies preserve the Location header.","Log redirect chains for indexer endpoints to catch stripping early.","Prefer direct .torrent URLs over redirect-dependent ones."],"tags":["http","redirect","torrent","indexer","webexception"],"backgroundTag":null,"analyzedSha":"da2284d7eaab22ed9b2ca698af690148d691e967","analyzedAt":"2026-08-13T15:53:02.562Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}