[GH-ISSUE #15468] x/imagegen/transfer: disk write errors silently ignored in downloader copy(), causing silent data corruption #71946

Open
opened 2026-05-05 03:07:19 -05:00 by GiteaMirror · 2 comments
Owner

Originally created by @kuishou68 on GitHub (Apr 10, 2026).
Original GitHub issue: https://github.com/ollama/ollama/issues/15468

Bug Report

Summary

In x/imagegen/transfer/download.go, the copy() function ignores the error returned by dst.Write(). This causes silent data corruption when downloading blobs: if a disk-write fails (e.g. disk full, I/O error, permission error), the function continues as if nothing happened, the SHA256 hash still validates against the received bytes (not written bytes), and the download is reported as successful — but the on-disk file is corrupt or incomplete.

Affected File

x/imagegen/transfer/download.go, function copy()

Code

nr, err := src.Read(buf)
if nr > 0 {
    lastRead.Store(time.Now().UnixNano())
    dst.Write(buf[:nr])   // ← error return value is discarded!
    h.Write(buf[:nr])     // hash counts bytes regardless of whether write succeeded
    d.progress.add(int64(nr))
    n += int64(nr)
}

Impact

  • Disk full: If the disk runs out of space mid-download, writes silently fail. The SHA256 hash is computed over bytes received from the network (not bytes on disk), so the hash check passes. The resulting file is silently truncated/corrupt.
  • I/O errors: Any transient or persistent disk I/O error is dropped; the download reports success.
  • This is especially dangerous because the hash verification if got := fmt.Sprintf("sha256:%x", h.Sum(nil)); got != blob.Digest is meant to be the final correctness check, but it can falsely pass when writes fail.

Expected Behavior

The error from dst.Write() should be checked and returned immediately, causing the download to fail and retry (or report an error to the user).

Fix

if nw, werr := dst.Write(buf[:nr]); werr != nil {
    return n, werr
} else if nw != nr {
    return n, io.ErrShortWrite
}

Steps to Reproduce

  1. Start a large blob download via the imagegen transfer package
  2. Fill the disk to capacity mid-download
  3. Observe that the download reports "success" but the file is corrupt (truncated)

Environment

  • Introduced in the recent x/imagegen/transfer package (new code, not yet in production stable releases but shipping in latest main)
Originally created by @kuishou68 on GitHub (Apr 10, 2026). Original GitHub issue: https://github.com/ollama/ollama/issues/15468 ## Bug Report ### Summary In `x/imagegen/transfer/download.go`, the `copy()` function ignores the error returned by `dst.Write()`. This causes **silent data corruption** when downloading blobs: if a disk-write fails (e.g. disk full, I/O error, permission error), the function continues as if nothing happened, the SHA256 hash still validates against the *received* bytes (not *written* bytes), and the download is reported as successful — but the on-disk file is corrupt or incomplete. ### Affected File `x/imagegen/transfer/download.go`, function `copy()` ### Code ```go nr, err := src.Read(buf) if nr > 0 { lastRead.Store(time.Now().UnixNano()) dst.Write(buf[:nr]) // ← error return value is discarded! h.Write(buf[:nr]) // hash counts bytes regardless of whether write succeeded d.progress.add(int64(nr)) n += int64(nr) } ``` ### Impact - **Disk full**: If the disk runs out of space mid-download, writes silently fail. The SHA256 hash is computed over bytes received from the network (not bytes on disk), so the hash check passes. The resulting file is silently truncated/corrupt. - **I/O errors**: Any transient or persistent disk I/O error is dropped; the download reports success. - This is especially dangerous because the hash verification `if got := fmt.Sprintf("sha256:%x", h.Sum(nil)); got != blob.Digest` is meant to be the final correctness check, but it can falsely pass when writes fail. ### Expected Behavior The error from `dst.Write()` should be checked and returned immediately, causing the download to fail and retry (or report an error to the user). ### Fix ```go if nw, werr := dst.Write(buf[:nr]); werr != nil { return n, werr } else if nw != nr { return n, io.ErrShortWrite } ``` ### Steps to Reproduce 1. Start a large blob download via the imagegen transfer package 2. Fill the disk to capacity mid-download 3. Observe that the download reports "success" but the file is corrupt (truncated) ### Environment - Introduced in the recent `x/imagegen/transfer` package (new code, not yet in production stable releases but shipping in latest main)
Author
Owner

@kuishou68 commented on GitHub (Apr 10, 2026):

I've opened PR #15469 to fix this issue.

<!-- gh-comment-id:4219119151 --> @kuishou68 commented on GitHub (Apr 10, 2026): I've opened PR #15469 to fix this issue.
Author
Owner

@PureBlissAK commented on GitHub (Apr 18, 2026):

🤖 Automated Triage & Analysis Report

Issue: #15468
Analyzed: 2026-04-18T18:21:10.776882

Analysis

  • Type: unknown
  • Severity: medium
  • Components: unknown

Implementation Plan

  • Effort: medium
  • Steps:

This issue has been triaged and marked for implementation.

<!-- gh-comment-id:4274307858 --> @PureBlissAK commented on GitHub (Apr 18, 2026): <!-- ollama-issue-orchestrator:v1 issue:15468 --> ## 🤖 Automated Triage & Analysis Report **Issue**: #15468 **Analyzed**: 2026-04-18T18:21:10.776882 ### Analysis - **Type**: unknown - **Severity**: medium - **Components**: unknown ### Implementation Plan - **Effort**: medium - **Steps**: *This issue has been triaged and marked for implementation.*
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/ollama#71946