From 2407f97c28a12f8cab57fc76235bf9c2c910648b Mon Sep 17 00:00:00 2001 From: CMGS Date: Thu, 2 Jul 2026 20:39:18 +0800 Subject: [PATCH] fix(image): retry oras-go pull on transient registry stream drops The native oras-go pull (unlike the CI's pull_image) had no retry, so pulling a multi-GB tahoe/sequoia base from ghcr fails outright on the intermittent 'stream error ... PROTOCOL_ERROR received from peer' HTTP/2 drop. Retry the fetch+import up to 3x with backoff (mid-stream can't resume, so re-fetch). --- cmd/image/handler.go | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/cmd/image/handler.go b/cmd/image/handler.go index d7413c3..dd44cff 100644 --- a/cmd/image/handler.go +++ b/cmd/image/handler.go @@ -48,12 +48,30 @@ func (h *Handler) Pull(cmd *cobra.Command, args []string) error { // blob straight into the store. Credentials still come from the user's docker config (public // images pull anonymously), so no external oras binary is needed. logger.Debugf(ctx, "pulling OCI artifact %s via oras-go", ref) - rc, err := pullOCILayer(ctx, ref) - if err != nil { - return err + // retry transient registry stream drops: ghcr resets the HTTP/2 stream on multi-GB blobs with + // PROTOCOL_ERROR mid-copy. A fresh fetch (from the start — mid-stream can't resume) usually wins. + var perr error + for attempt := 1; attempt <= 3; attempt++ { + rc, ferr := pullOCILayer(ctx, ref) + if ferr != nil { + perr = ferr + } else { + perr = s.ImportFromReader(ctx, ref, progress.Nop, rc) + _ = rc.Close() + } + if perr == nil { + return nil + } + logger.Warnf(ctx, "oras pull attempt %d/3 failed: %v", attempt, perr) + if attempt < 3 { + select { + case <-ctx.Done(): + return ctx.Err() + case <-time.After(time.Duration(attempt) * 10 * time.Second): + } + } } - defer func() { _ = rc.Close() }() - return s.ImportFromReader(ctx, ref, progress.Nop, rc) + return fmt.Errorf("pull %s after 3 attempts: %w", ref, perr) } // List renders stored images as a table (NAME TYPE SIZE DIGEST CREATED), or JSON with -o json.