{"record":{"id":"7aa8c3d06f87701e","repo":"docker/compose","slug":"creating-fetcher-for-s-w","errorCode":null,"errorMessage":"creating fetcher for %s: %w","messagePattern":"creating fetcher for (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/oci/resolver.go","lineNumber":106,"sourceCode":"\tfetch, err := fetcher.Fetch(ctx, descriptor)\n\tif err != nil {\n\t\treturn spec.Descriptor{}, nil, err\n\t}\n\tcontent, err := io.ReadAll(fetch)\n\tif err != nil {\n\t\treturn spec.Descriptor{}, nil, err\n\t}\n\treturn descriptor, content, nil\n}\n\n// 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 {","sourceCodeStart":88,"sourceCodeEnd":124,"githubUrl":"https://github.com/docker/compose/blob/ddc4b044b62e9f715212ea4143fa830fac76382f/internal/oci/resolver.go#L88-L124","documentation":"GetBlob asks the containerd remotes.Resolver for a Fetcher bound to the repository reference; if that fails (auth, repository does not exist, resolver misconfiguration, unreachable registry) the error is wrapped with the ref. This happens before any blob request is made, so it always indicates a reference/registry-level problem, not a problem with the specific blob.","triggerScenarios":"resolver.Fetcher(ctx, ref.String()) failing: unauthenticated pull from a private repo, expired registry token/credentials, typo'd repository name in the ref, network/DNS failure reaching the registry, or a resolver built without the right auth handler.","commonSituations":"docker compose pull/push of an OCI artifact from a private registry without docker login; stale cached credentials; corporate proxies intercepting registry TLS; refs normalized incorrectly (missing namespace/tag).","solutions":["Authenticate against the registry: docker login <registry> (or configure the resolver's auth).","Verify the ref: the repository must exist and the name be fully qualified (registry/account/repo).","Check connectivity/TLS: curl -v https://<registry>/v2/ and inspect proxy/CA settings.","Re-run with debug logging to see the wrapped containerd error, which names the real cause (401, 404, TLS, DNS)."],"exampleFix":"# before\n$ docker compose --project-name demo pull   # not logged in to private registry\n\n# after\n$ docker login registry.example.com\n$ docker compose --project-name demo pull","handlingStrategy":"try-catch","validationCode":"// preflight: does the repo resolve and are credentials in place?\nif _, err := resolver.Resolve(ctx, ref.String()); err != nil {\n    return fmt.Errorf(\"cannot access %s (auth/repo): %w\", ref, err)\n}","typeGuard":null,"tryCatchPattern":"fetcher, err := resolver.Fetcher(ctx, ref.String())\nif err != nil {\n    if errors.Is(err, errdefs.ErrUnauthorized) || errors.Is(err, errdefs.ErrNotFound) {\n        // guide the user: login or check repo name\n    }\n    return fmt.Errorf(\"creating fetcher for %s: %w\", ref, err)\n}","preventionTips":["docker login before pulling/pushing private artifacts.","Fully qualify refs (registry/namespace/repo).","Surface the wrapped containerd error; it distinguishes 401 vs 404 vs TLS."],"tags":["oci","registry","auth","resolver","network"],"backgroundTag":null,"analyzedSha":"ddc4b044b62e9f715212ea4143fa830fac76382f","analyzedAt":"2026-08-15T13:31:42.319Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}