docker/cli · error

error pinging v2 registry

Error message

error pinging v2 registry: %w

What it means

Root transport error from getHTTPTransport: registry.PingV2Registry GETs the /v2/ endpoint to learn the auth challenges, and any failure (connection refused, TLS error, non-2xx, non-v2 registry) is wrapped here. It is the concrete cause that 601 wraps, so most "failed to configure transport" reports trace back to this.

Solutions

  1. Run curl -v https://<host>/v2/ to see the exact HTTP/TLS failure.
  2. If the cert is private/self-signed, enable insecure mode (insecure=true / --insecure-registry).
  3. Confirm the registry software implements the OCI/Docker distribution v2 API.
  4. Verify DNS resolution and reachability (port open, no firewall).
  5. Re-authenticate with `docker login <host>` if the ping is failing on auth.

Example fix

$ curl -v https://registry.example.com/v2/
# if self-signed cert error, enable insecure mode:
cli := registryclient.NewRegistryClient(resolver, ua, true)
Defensive patterns

Strategy: validation

Validate before calling

// Manual v2 ping mirroring what the client does internally.
func canPingV2(ctx context.Context, regURL string, insecure bool) error {
    tr := &http.Transport{}
    if insecure {
        tr.TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
    }
    c := &http.Client{Transport: tr, Timeout: 10 * time.Second}
    req, _ := http.NewRequestWithContext(ctx, "GET", regURL+"/v2/", nil)
    resp, err := c.Do(req)
    if err != nil {
        return err
    }
    defer resp.Body.Close()
    if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusUnauthorized {
        return fmt.Errorf("unexpected v2 ping status %s", resp.Status)
    }
    return nil
}

Try / catch

// Differentiate retryable network errors from fatal TLS/config errors.
if errors.Is(err, context.DeadlineExceeded) || isConnRefused(err) {
    // retry with backoff
} else if isTLSerr(err) {
    // prompt user about insecure mode / CA bundle
}

Prevention

When it happens

Trigger: The registry host is unreachable, the TLS certificate is invalid or self-signed (and insecure mode is off), the registry does not implement the distribution v2 API, or the /v2/ ping returns an error status before auth can proceed.

Common situations: Wrong registry URL; self-signed cert without insecure flag; registry behind a proxy that mangles /v2/; legacy v1-only registry; DNS failure; corporate firewall blocking the host.

Related errors


AI-assisted analysis of docker/cli@4f84911bfe (2026-08-07). Data as JSON: /api/errors/cdc31fd858a6538d. Report an issue: GitHub.

Appendix: source

Thrown at internal/registryclient/endpoint.go:85

// getHTTPTransport builds a transport for use in communicating with a registry
func getHTTPTransport(authConfig registrytypes.AuthConfig, endpoint registry.APIEndpoint, repoName, userAgent string, actions []string) (http.RoundTripper, error) {
	// get the http transport, this will be used in a client to upload manifest
	base := &http.Transport{
		Proxy: http.ProxyFromEnvironment,
		Dial: (&net.Dialer{
			Timeout:   30 * time.Second,
			KeepAlive: 30 * time.Second,
		}).Dial,
		TLSHandshakeTimeout: 10 * time.Second,
		TLSClientConfig:     endpoint.TLSConfig,
		DisableKeepAlives:   true,
	}

	modifiers := registry.Headers(userAgent, http.Header{})
	authTransport := transport.NewTransport(base, modifiers...)
	challengeManager, err := registry.PingV2Registry(endpoint.URL, authTransport)
	if err != nil {
		return nil, fmt.Errorf("error pinging v2 registry: %w", err)
	}
	if authConfig.RegistryToken != "" {
		passThruTokenHandler := &existingTokenHandler{token: authConfig.RegistryToken}
		modifiers = append(modifiers, auth.NewAuthorizer(challengeManager, passThruTokenHandler))
	} else {
		if len(actions) == 0 {
			actions = []string{"pull"}
		}
		creds := &staticCredentialStore{authConfig: &authConfig}
		tokenHandler := auth.NewTokenHandler(authTransport, creds, repoName, actions...)
		basicHandler := auth.NewBasicHandler(creds)
		modifiers = append(modifiers, auth.NewAuthorizer(challengeManager, tokenHandler, basicHandler))
	}
	return transport.NewTransport(base, modifiers...), nil
}

type existingTokenHandler struct {
	token string

View on GitHub (pinned to 4f84911bfe)