From db21c47a7691ac0baf304a84ade911ca4eed2ec8 Mon Sep 17 00:00:00 2001 From: localai-org-maint-bot Date: Sat, 15 Aug 2026 18:07:17 +0200 Subject: [PATCH] fix(downloader): retry checksum mismatches (#11536) A remote can serve stale or corrupted bytes for one request. Mark the integrity failure as transient so the bounded download planner retries it. Assisted-by: Codex:gpt-5.6 Co-authored-by: localai-org-maint-bot <306269227+localai-org-maint-bot@users.noreply.github.com> --- pkg/downloader/retry_test.go | 31 +++++++++++++++++++++++++++++++ pkg/downloader/uri.go | 2 +- 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/pkg/downloader/retry_test.go b/pkg/downloader/retry_test.go index 5fca56440..dc949e09e 100644 --- a/pkg/downloader/retry_test.go +++ b/pkg/downloader/retry_test.go @@ -179,6 +179,37 @@ var _ = Describe("DownloadFilesWithContext retries", func() { } }) + It("retries a checksum mismatch", func() { + wrongPayload := []byte("stale model bytes") + requests := 0 + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + requests++ + body := payload + if requests == 1 { + body = wrongPayload + } + w.Header().Set("Content-Length", strconv.Itoa(len(body))) + w.WriteHeader(http.StatusOK) + _, _ = w.Write(body) + })) + DeferCleanup(server.Close) + + err := downloader.DownloadFilesWithContext(context.Background(), []downloader.FileTask{{ + URI: downloader.URI(server.URL), + Destination: destPath, + SHA256: payloadSHA, + FileIndex: 1, + TotalFiles: 1, + }}, nil) + Expect(requests).To(Equal(2), "the checksum failure must trigger one retry") + Expect(err).ToNot(HaveOccurred()) + + got, err := os.ReadFile(destPath) + Expect(err).ToNot(HaveOccurred()) + Expect(got).To(Equal(payload)) + Expect(destPath + downloader.PartialFileSuffix).ToNot(BeAnExistingFile()) + }) + It("does not retry a permanent failure", func() { attempts := 0 server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { diff --git a/pkg/downloader/uri.go b/pkg/downloader/uri.go index 023978130..90df65b0a 100644 --- a/pkg/downloader/uri.go +++ b/pkg/downloader/uri.go @@ -850,7 +850,7 @@ func (uri URI) DownloadFileWithContext(ctx context.Context, filePath, sha string if calculatedSHA != sha { xlog.Debug("SHA mismatch for file", "file", filePath, "calculated", calculatedSHA, "metadata", sha) _ = removePartialFile(tmpFilePath) - return fmt.Errorf("SHA mismatch for file %q ( calculated: %s != metadata: %s )", filePath, calculatedSHA, sha) + return asTransient(fmt.Errorf("SHA mismatch for file %q ( calculated: %s != metadata: %s )", filePath, calculatedSHA, sha)) } } else { // Visible at the default log level so missing-digest configs are