Skip to content

fix(oci): retry layer downloads on transient network errors#10579

Merged
mudler merged 1 commit into
masterfrom
fix/oci-layer-retry
Jun 28, 2026
Merged

fix(oci): retry layer downloads on transient network errors#10579
mudler merged 1 commit into
masterfrom
fix/oci-layer-retry

Conversation

@localai-bot

Copy link
Copy Markdown
Collaborator

Problem

Fixes #10577.

Installing large backend images through the Web UI (e.g. vllm / vllm-omni, which are several GiB) intermittently fails with:

Failed to install backend: ... failed to download image tar: failed to download layer 0: unexpected EOF

The reporter guessed it was a file-size threshold. It isn't - it's that a large layer takes long enough that the single connection to the registry occasionally drops mid-stream. The download is not resumable, so each retry from the UI restarts from zero and tends to hit the same blip, which is why it reads as a consistent, size-correlated failure. This has been reported more than once.

Root cause

pkg/oci/image.go already defines defaultRetryPredicate (matching unexpected EOF, EOF, EPIPE, ECONNRESET, connection refused) and wires it into the registry transport for manifest/digest fetches (GetImage, GetImageDigest). But the actual layer data stream in DownloadOCIImageTar bypassed it: layer.Compressed() + xio.Copy ran exactly once with no retry and no recovery.

Fix

Extract the per-layer copy into downloadLayerToFile, which retries on the same transient errors with exponential backoff, truncating any partial data before each retry. Non-retryable errors and context cancellation still fail fast. Default is 3 retries (4 attempts total).

Tests

Added internal unit tests (pkg/oci/layer_internal_test.go) with a fake v1.Layer that drops the stream mid-transfer:

  • retries on unexpected EOF and writes the complete layer (verifies partial data is discarded)
  • does not retry on a non-retryable error (fails fast, single attempt)
  • gives up after exhausting retries on a persistent transient error

Full pkg/oci suite passes (including the live registry pull); golangci-lint --new-from-merge-base=origin/master is clean.

Note (out of scope)

The reporter has an NVIDIA RTX 3060 but the failing image was the ROCm/hipblas variant (...-gpu-rocm-hipblas-vllm-omni). Even with this download fix, that backend won't run on their hardware - worth a separate look at meta-backend variant selection / what the UI offered. Not addressed here.


Assisted-by: Claude:claude-opus-4-8 [Claude Code]

Installing large backend images (e.g. vLLM/vLLM-omni, several GiB) over
the Web UI could fail with "failed to download layer 0: unexpected EOF"
when a single connection to the registry dropped mid-stream. The whole
install then failed with no recovery, and since the download is not
resumable, retrying from the UI restarted from zero and usually hit the
same blip again - so users saw it as a consistent, size-correlated
failure (issue #10577).

The registry transport already retries manifest/digest fetches via
defaultRetryPredicate (GetImage/GetImageDigest), but the per-layer data
stream in DownloadOCIImageTar bypassed it entirely: layer.Compressed()
+ xio.Copy ran exactly once.

Extract the per-layer copy into downloadLayerToFile, which retries on the
same transient errors (unexpected EOF, EOF, EPIPE, ECONNRESET, connection
refused) with exponential backoff, truncating any partial data before
each retry. Non-retryable errors and context cancellation still fail
fast.

Signed-off-by: Ettore Di Giacinto <mudler@localai.io>
Assisted-by: Claude:claude-opus-4-8 [Claude Code]
@mudler
mudler merged commit 323b57a into master Jun 28, 2026
60 checks passed
@mudler
mudler deleted the fix/oci-layer-retry branch June 28, 2026 19:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

failed to download image tar: failed to download layer 0: unexpected EOF

2 participants