{"record":{"id":"de17a8b7d52d6054","repo":"docker/compose","slug":"reading-blob-s-w","errorCode":null,"errorMessage":"reading blob %s: %w","messagePattern":"reading blob (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/oci/resolver.go","lineNumber":117,"sourceCode":"// GetBlob retrieves the content of a blob descriptor (e.g. an artifact layer)\n// from the repository ref belongs to. Unlike Get it doesn't Resolve the\n// digest, as the registry manifests endpoint only serves actual manifests;\n// blob content must be fetched directly from the blobs endpoint.\nfunc GetBlob(ctx context.Context, resolver remotes.Resolver, ref reference.Named, descriptor spec.Descriptor) ([]byte, error) {\n\tfetcher, err := resolver.Fetcher(ctx, ref.String())\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"creating fetcher for %s: %w\", ref, err)\n\t}\n\tfetch, err := fetcher.Fetch(ctx, descriptor)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"fetching blob %s: %w\", descriptor.Digest, err)\n\t}\n\tdefer func() { _ = fetch.Close() }()\n\t// bound the read by the declared size so a rogue registry can't cause\n\t// unbounded allocation; the extra byte detects oversized responses.\n\tcontent, err := io.ReadAll(io.LimitReader(fetch, descriptor.Size+1))\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"reading blob %s: %w\", descriptor.Digest, err)\n\t}\n\tif int64(len(content)) != descriptor.Size {\n\t\treturn nil, fmt.Errorf(\"blob %s size mismatch: expected %d bytes, got %d\", descriptor.Digest, descriptor.Size, len(content))\n\t}\n\t// GetBlob bypasses containerd's content store, so integrity must be\n\t// checked here before callers write the bytes to disk.\n\tif err := descriptor.Digest.Validate(); err != nil {\n\t\treturn nil, fmt.Errorf(\"invalid digest %s: %w\", descriptor.Digest, err)\n\t}\n\tif actual := descriptor.Digest.Algorithm().FromBytes(content); actual != descriptor.Digest {\n\t\treturn nil, fmt.Errorf(\"blob digest mismatch: expected %s, got %s\", descriptor.Digest, actual)\n\t}\n\treturn content, nil\n}\n\nfunc Copy(ctx context.Context, resolver remotes.Resolver, image reference.Named, named reference.Named) (spec.Descriptor, error) {\n\tsrc, desc, err := resolver.Resolve(ctx, image.String())\n\tif err != nil {","sourceCodeStart":99,"sourceCodeEnd":135,"githubUrl":"https://github.com/docker/compose/blob/ddc4b044b62e9f715212ea4143fa830fac76382f/internal/oci/resolver.go#L99-L135","documentation":"The blob request succeeded but reading the response body (io.ReadAll over a LimitReader bounded by descriptor.Size+1) failed mid-transfer. This wraps the underlying I/O error with the digest: network reset, TLS renegotiation, proxy truncation, or the registry closing the stream early. The +1-byte bound means this is not a size problem (that is error 95) but a transport/read failure.","triggerScenarios":"fetcher.Fetch's Read fails partway: connection reset between registry and client, proxy idle-timeout killing long blob downloads, flaky VPN/Wi-Fi, registry closing the stream on internal error.","commonSituations":"Large compose artifact layers downloaded over unstable links; corporate proxies with aggressive timeouts; CDN edge nodes dropping slow streams; ephemeral network blips during docker compose pull.","solutions":["Retry the pull — transient transport errors are the most common cause.","If it fails repeatedly at the same blob, bypass intermediaries (VPN/proxy) or raise proxy read timeouts.","Check registry/CDN health and logs for aborted uploads/GC races.","Reduce artifact size (fewer/smaller layers) if timeouts keep truncating the stream."],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"content, err := io.ReadAll(io.LimitReader(fetch, descriptor.Size+1))\nif err != nil {\n    if isTransientIOErr(err) { // reset, timeout, EOF mid-stream\n        return retryGetBlob(ctx, resolver, ref, descriptor) // bounded retries\n    }\n    return nil, fmt.Errorf(\"reading blob %s: %w\", descriptor.Digest, err)\n}","preventionTips":["Retry transient transport failures with backoff.","Avoid proxies/VPNs that truncate long downloads.","Keep artifacts small enough for your network's stability window."],"tags":["oci","registry","blob","io","network"],"backgroundTag":null,"analyzedSha":"ddc4b044b62e9f715212ea4143fa830fac76382f","analyzedAt":"2026-08-15T13:31:42.319Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}