{"record":{"id":"e97999cde3a9f526","repo":"abiosoft/colima","slug":"error-downloading-sha-file-from-s-w","errorCode":null,"errorMessage":"error downloading SHA file from '%s': %w","messagePattern":"error downloading SHA file from '(.+?)': %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"util/downloader/sha.go","lineNumber":107,"sourceCode":"\t\t\treturn err\n\t\t}\n\t\ts.Digest = digest\n\t}\n\n\treturn s.validateFile(filename)\n}\n\n// fetchSHAFromURL fetches SHA checksum file and extracts digest for the target file\nfunc fetchSHAFromURL(shaURL, targetFilename string) (string, error) {\n\tctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)\n\tdefer cancel()\n\n\tclient := NewHTTPClient()\n\n\t// fetch SHA file content\n\tdata, err := client.Fetch(ctx, shaURL)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"error downloading SHA file from '%s': %w\", shaURL, err)\n\t}\n\n\t// parse SHA file to find the matching entry\n\tdigest, err := parseSHAContent(data, targetFilename)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"error parsing SHA file from '%s': %w\", shaURL, err)\n\t}\n\n\treturn digest, nil\n}\n\n// parseSHAContent reads SHA checksum content and extracts the digest for the target filename.\n// Supports formats:\n//   - GNU coreutils: \"<hash>  <filename>\" (two spaces)\n//   - BSD/binary mode: \"<hash> *<filename>\" (space + asterisk)\nfunc parseSHAContent(data []byte, targetFilename string) (string, error) {\n\tscanner := bufio.NewScanner(bytes.NewReader(data))\n\tfor scanner.Scan() {","sourceCodeStart":89,"sourceCodeEnd":125,"githubUrl":"https://github.com/abiosoft/colima/blob/c3a5f9184d83a197184f897a9f07eb3c01b3bc88/util/downloader/sha.go#L89-L125","documentation":"fetchSHAFromURL uses client.Fetch with a 30-second timeout to retrieve the checksum file and that fetch failed. The wrapped error is a *NetworkError (DNS/connect/timeout, including exceeding the 30s budget) or *HTTPStatusError (status >= 400, e.g. the checksum URL 404s). The artifact download is aborted because its digest cannot be established.","triggerScenarios":"Checksum URL wrong or the file was removed (404); checksum host slow enough to exceed the 30s timeout; DNS or proxy failure specific to the checksum host.","commonSituations":"Mirrors that publish binaries but not checksums; sha URL templated from a different release than the artifact URL; rate-limited hosts.","solutions":["curl the checksum URL and confirm it returns the expected file","Point SHA.URL at the checksum file of the exact release as the artifact URL","Retry transient timeouts","If upstream publishes no checksums at all, drop the SHA field from the Request"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":"func isRetryableFetch(err error) bool {\n    var ne *downloader.NetworkError\n    if errors.As(err, &ne) {\n        return true\n    }\n    var he *downloader.HTTPStatusError\n    if errors.As(err, &he) {\n        return he.StatusCode >= 500 || he.StatusCode == 429\n    }\n    return false\n}","tryCatchPattern":"cacheFile, err := downloader.Download(host, req)\nif err != nil {\n    var fetchErr error = err\n    for attempt := 0; attempt < 3 && isRetryableFetch(fetchErr); attempt++ {\n        time.Sleep(time.Duration(attempt+1) * 2 * time.Second)\n        cacheFile, fetchErr = downloader.Download(host, req)\n    }\n    if fetchErr != nil {\n        return fetchErr // 404 on the sha URL needs a URL fix, not retries\n    }\n}","preventionTips":["Point SHA.URL at the same release/directory as the artifact URL","Verify checksum URLs when pinning versions; mirrors restructure checksum layouts","Respect the 30s fetch budget — host the checksum near the artifact"],"tags":["network","sha","download","retry"],"backgroundTag":null,"analyzedSha":"c3a5f9184d83a197184f897a9f07eb3c01b3bc88","analyzedAt":"2026-08-15T18:58:08.334Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}