{"record":{"id":"57c4270f343ef1f3","repo":"juanfont/headscale","slug":"checking-local-image-availability-w","errorCode":null,"errorMessage":"checking local image availability: %w","messagePattern":"checking local image availability: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/hi/docker.go","lineNumber":531,"sourceCode":"func checkImageAvailableLocally(ctx context.Context, cli *client.Client, imageName string) (bool, error) {\n\t_, _, err := cli.ImageInspectWithRaw(ctx, imageName) //nolint:staticcheck // SA1019: deprecated but functional\n\tif err != nil {\n\t\tif client.IsErrNotFound(err) { //nolint:staticcheck // SA1019: deprecated but functional\n\t\t\treturn false, nil\n\t\t}\n\n\t\treturn false, fmt.Errorf(\"inspecting image %s: %w\", imageName, err)\n\t}\n\n\treturn true, nil\n}\n\n// ensureImageAvailable pulls imageName if missing, using Docker Hub\n// credentials and retrying transient errors.\nfunc ensureImageAvailable(ctx context.Context, cli *client.Client, imageName string, verbose bool) error {\n\tavailable, err := checkImageAvailableLocally(ctx, cli, imageName)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"checking local image availability: %w\", err)\n\t}\n\n\tif available {\n\t\tif verbose {\n\t\t\tlog.Printf(\"Image %s is available locally\", imageName)\n\t\t}\n\n\t\treturn nil\n\t}\n\n\tif verbose {\n\t\tlog.Printf(\"Image %s not found locally, pulling...\", imageName)\n\t}\n\n\tregistryAuth, err := dockertestutil.RegistryAuth()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"resolving registry auth: %w\", err)\n\t}","sourceCodeStart":513,"sourceCodeEnd":549,"githubUrl":"https://github.com/juanfont/headscale/blob/565fd254d06c4c7f9a8cad1714a43445c79ba420/cmd/hi/docker.go#L513-L549","documentation":"Returned by `ensureImageAvailable` when its first step, `checkImageAvailableLocally`, itself errored (i.e. the 'inspecting image %s' wrapper bubbled up). It marks the availability-check stage so the later pull stage is never reached. Root causes are daemon-side, not 'image missing' — a missing image is a normal result that triggers a pull instead.","triggerScenarios":"Same underlying set as the inspect error: daemon down, socket permission denied, API errors on ImageInspectWithRaw, cancelled context before the run starts.","commonSituations":"Running `hi` without Docker running; group membership not refreshed after adding user to docker group; DOCKER_HOST pointing to a stale remote daemon; CI service container for dockerd not yet ready when `hi run` starts.","solutions":["Start/verify Docker: `docker info`.","Wait for dockerd readiness in CI before invoking `hi run`.","Check DOCKER_HOST / docker context points at a live daemon.","Re-login after changing docker group membership."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// readiness gate before running tests\nif _, err := cli.Ping(ctx); err != nil {\n    return fmt.Errorf(\"docker not ready: %w\", err)\n}","typeGuard":null,"tryCatchPattern":"if err := runDockerTest(ctx, config); err != nil {\n    if strings.Contains(err.Error(), \"checking local image availability\") {\n        // daemon unreachable at startup: bring Docker up, then re-run\n    }\n}","preventionTips":["Gate CI jobs on dockerd readiness before invoking hi.","Verify DOCKER_HOST/docker context target is alive.","Re-login after adding the user to the docker group."],"tags":["docker","image-inspect","readiness","daemon"],"backgroundTag":null,"analyzedSha":"565fd254d06c4c7f9a8cad1714a43445c79ba420","analyzedAt":"2026-08-15T13:12:30.133Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}