From 641b5497b4d97c8a2d28296d22d3f3dff898826c Mon Sep 17 00:00:00 2001 From: Lili Wilson Date: Wed, 18 Feb 2026 19:08:47 +0000 Subject: [PATCH] fix: detect image pull errors from Docker progress stream Previously, pullImage discarded the Docker pull progress stream with io.Discard and only checked for IO errors. Docker reports many pull failures (rate limits, auth errors, image-not-found for specific platforms) as JSON messages within the progress stream, not as the initial error return. This caused silent pull failures followed by a confusing 'No such image' error from ContainerCreate. Now we decode each JSON message in the stream and surface any error immediately with a clear message. Co-Authored-By: Warp --- internal/worker/worker.go | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/internal/worker/worker.go b/internal/worker/worker.go index d60e49d..0f28643 100644 --- a/internal/worker/worker.go +++ b/internal/worker/worker.go @@ -377,9 +377,24 @@ func (w *Worker) pullImage(ctx context.Context, imageName string, authStr string } }() - // The image pull doesn't actually happen until you read from this stream, but we don't need the output. - if _, err = io.Copy(io.Discard, reader); err != nil { - return fmt.Errorf("failed to read image pull output: %w", err) + // Docker reports many pull failures (rate limits, auth errors, image-not-found for + // specific platforms) as JSON messages within the progress stream rather than as the + // initial error return. We must decode and inspect each message to detect these. + type pullMessage struct { + Error string `json:"error"` + } + decoder := json.NewDecoder(reader) + for { + var msg pullMessage + if err := decoder.Decode(&msg); err != nil { + if err == io.EOF { + break + } + return fmt.Errorf("failed to read image pull output for %s: %w", imageName, err) + } + if msg.Error != "" { + return fmt.Errorf("failed to pull image %s: %s", imageName, msg.Error) + } } log.Infof(ctx, "Successfully pulled image: %s", imageName) return nil