{"record":{"id":"cf8175cf8916d143","repo":"abiosoft/colima","slug":"error-resolving-download-url-s-w","errorCode":null,"errorMessage":"error resolving download URL '%s': %w","messagePattern":"error resolving download URL '(.+?)': %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"util/downloader/native.go","lineNumber":41,"sourceCode":"\t}\n\n\t// get existing file size for resume\n\tvar existingSize int64\n\tif stat, err := os.Stat(destPath); err == nil {\n\t\texistingSize = stat.Size()\n\t}\n\n\t// create HTTP client\n\tclient := NewHTTPClient()\n\n\t// use a long timeout for large files (2 hours)\n\tctx, cancel := context.WithTimeout(context.Background(), 2*time.Hour)\n\tdefer cancel()\n\n\t// get final URL (follows redirects)\n\tfinalURL, err := client.GetFinalURL(ctx, r.URL)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error resolving download URL '%s': %w\", r.URL, err)\n\t}\n\n\t// download the file\n\tresult, err := client.Download(ctx, DownloadOptions{\n\t\tURL:            finalURL,\n\t\tDestPath:       destPath,\n\t\tExpectedETag:   resumeInfo.ETag,\n\t\tResumeFromByte: existingSize,\n\t\tShowProgress:   true,\n\t})\n\tif err != nil {\n\t\t// save resume info for next attempt if we have ETag\n\t\tif result != nil && result.ETag != \"\" {\n\t\t\td.saveResumeInfo(r.URL, result.ETag, existingSize)\n\t\t}\n\t\treturn fmt.Errorf(\"error downloading '%s': %w\", path.Base(r.URL), err)\n\t}\n","sourceCodeStart":23,"sourceCodeEnd":59,"githubUrl":"https://github.com/abiosoft/colima/blob/c3a5f9184d83a197184f897a9f07eb3c01b3bc88/util/downloader/native.go#L23-L59","documentation":"The pre-flight HEAD via GetFinalURL failed, so the actual GET never starts. The wrapped error is either *NetworkError (DNS failure, connection refused/timeout — errors.go renders friendly DNS/timeout text) or *HTTPStatusError (status >= 400 after following up to 10 redirects, e.g. 404 for a removed asset, 403/429 rate-limiting, or 405 from servers that reject HEAD).","triggerScenarios":"DNS cannot resolve the host; proxy/firewall blocks the HEAD request; artifact URL pins a version that no longer exists (404); GitHub rate limits releases (403/429); server answers HEAD with 405.","commonSituations":"Pinned version no longer published upstream; corporate proxies; mirrors that dropped files; typos in release URLs.","solutions":["Reproduce with curl -IL <url> and read the status line","Fix the URL/version in the download request for 404/410","Check DNS/proxy if curl fails the same way","Retry later only for 429 and 5xx; never for 404/403"],"exampleFix":"// before\nfinalURL, err := client.GetFinalURL(ctx, r.URL)\nif err != nil {\n    return err\n}\n// after: classify before deciding to retry\nfinalURL, err := client.GetFinalURL(ctx, r.URL)\nif err != nil {\n    var se *downloader.HTTPStatusError\n    if errors.As(err, &se) && (se.StatusCode >= 500 || se.StatusCode == 429) {\n        // transient: safe to retry with backoff\n    }\n}","handlingStrategy":"retry","validationCode":null,"typeGuard":"func classifyResolve(err error) (retryable bool, reason string) {\n    var ne *downloader.NetworkError\n    if errors.As(err, &ne) {\n        return true, \"network: \" + ne.Error()\n    }\n    var he *downloader.HTTPStatusError\n    if errors.As(err, &he) {\n        if he.StatusCode >= 500 || he.StatusCode == 429 {\n            return true, \"server busy\"\n        }\n        return false, he.Error() // 404/403: fix the URL, do not retry\n    }\n    return false, \"unknown\"\n}","tryCatchPattern":"var lastErr error\nfor attempt := 0; attempt < 3; attempt++ {\n    finalURL, lastErr = client.GetFinalURL(ctx, u)\n    if lastErr == nil {\n        break\n    }\n    if retryable, _ := classifyResolve(lastErr); !retryable {\n        return lastErr\n    }\n    time.Sleep(time.Duration(1<<attempt) * time.Second)\n}\nif lastErr != nil {\n    return lastErr\n}","preventionTips":["Smoke-test asset URLs (curl -IL) whenever a pinned version changes","Detect *HTTPStatusError and branch: 404/403 are permanent, 429/5xx are transient","Watch for HEAD-hostile servers (405) when adding new mirrors"],"tags":["network","http","download","retry"],"backgroundTag":null,"analyzedSha":"c3a5f9184d83a197184f897a9f07eb3c01b3bc88","analyzedAt":"2026-08-15T18:58:08.334Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}