{"record":{"id":"5d4dc71ed7eb0c23","repo":"SubtitleEdit/subtitleedit","slug":"the-requested-url-was-not-found-url","errorCode":null,"errorMessage":"The requested URL was not found: {url}","messagePattern":"The requested URL was not found: (.+?)","errorType":"exception","errorClass":"FileNotFoundException","httpStatus":null,"severity":"error","filePath":"src/ui/Logic/Download/DownloadHelper.cs","lineNumber":93,"sourceCode":"                }\n                else if (currentPosition > startPosition && destination.CanSeek)\n                {\n                    // No Range header will be sent, so the server returns the file from\n                    // byte 0 - rewind the partial bytes from the failed attempt, otherwise\n                    // the full body would be appended after them and corrupt the download.\n                    destination.Seek(startPosition, SeekOrigin.Begin);\n                    destination.SetLength(startPosition);\n                    currentPosition = startPosition;\n                }\n\n                using var response = await httpClient.SendAsync(\n                    request,\n                    HttpCompletionOption.ResponseHeadersRead,\n                    cts.Token).ConfigureAwait(false);\n\n                if (response.StatusCode == System.Net.HttpStatusCode.NotFound)\n                { \n                    throw new FileNotFoundException($\"The requested URL was not found: {url}\");\n                }\n\n                response.EnsureSuccessStatusCode();\n\n                // Get total size from headers\n                if (totalBytes == null)\n                {\n                    totalBytes = response.Content.Headers.ContentLength;\n\n                    // For range requests, get total from Content-Range header\n                    if (response.Content.Headers.ContentRange != null)\n                    {\n                        totalBytes = response.Content.Headers.ContentRange.Length;\n                    }\n                }\n\n                var totalReadBytes = currentPosition; // Start from current position\n","sourceCodeStart":75,"sourceCodeEnd":111,"githubUrl":"https://github.com/SubtitleEdit/subtitleedit/blob/17a9f0748781032255db3526b7215d2fb891e3af/src/ui/Logic/Download/DownloadHelper.cs#L75-L111","documentation":"Thrown by DownloadHelper.DownloadFileAsync when the HTTP response status is 404 NotFound. Rather than letting EnsureSuccessStatusCode raise a generic HttpRequestException, the helper detects 404 specifically and throws FileNotFoundException with the offending URL. This distinguishes 'the artifact does not exist upstream' from transient network errors so callers do not waste retry budget on a permanent condition.","triggerScenarios":"Any Get request inside DownloadFileAsync returns HTTP 404 — wrong release tag in the URL, asset renamed/removed from the GitHub release, wrong version pinned in the service's URL constant, or the CDN path was restructured. Note: the retry loop's catch filter excludes FileNotFoundException, so a 404 does NOT consume retries; it propagates immediately.","commonSituations":"Upstream GitHub release asset was renamed or deleted; ReleaseTag/BaseUrl constant is stale after an upgrade; typo in the assembled URL; mirror returned 404 because the file was unpublished; rate-limited request that the server answered with 404 instead of 403.","solutions":["Open the {url} from the error in a browser/curl to confirm it 404s upstream — if so, the asset is missing or moved.","Update the service's ReleaseTag / BaseUrl / file-name constant to the release that actually contains the asset.","If the URL looks correct, verify the host is reachable and not redirecting to a 404 login/CDN edge.","Re-run with verbose HttpClient logging to capture the resolved URL and any redirect chain."],"exampleFix":"// before: stale release tag yields 404\nprivate const string ReleaseTag = \"v1.0\";\n\n// after: pin to release that ships the asset\nprivate const string ReleaseTag = \"v1.4.2\";","handlingStrategy":"validation","validationCode":"// Probe the URL with a HEAD before invoking the download\nusing var head = await httpClient.SendAsync(new HttpRequestMessage(HttpMethod.Head, url), ct);\nif (head.StatusCode == HttpStatusCode.NotFound)\n    throw new InvalidOperationException($\"Asset missing upstream: {url}\");","typeGuard":null,"tryCatchPattern":"try { await DownloadHelper.DownloadFileAsync(http, url, fs, progress, ct); }\ncatch (FileNotFoundException ex) when (ex.Message.Contains(\"URL was not found\"))\n{ _logger.Error(\"Upstream 404 for {Url} — release tag or asset name is stale.\", url); throw; }","preventionTips":["Treat a 404 as a permanent failure (the helper already excludes it from retries).","Keep ReleaseTag/BaseUrl constants versioned with the upstream release.","Add a smoke-test that HEADs each known asset URL in CI."],"tags":["network","http-404","download","url","filenotfound"],"backgroundTag":null,"analyzedSha":"17a9f0748781032255db3526b7215d2fb891e3af","analyzedAt":"2026-08-13T18:11:43.374Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}