docker/cli · error

error establishing connection to trust repository

Error message

error establishing connection to trust repository: %w

What it means

In PushTrustedReference (trust_push.go:102-104), GetNotaryRepository failed to construct the authenticated notary client/transport, and the error is wrapped with 'error establishing connection to trust repository'. GetNotaryRepository (trust.go:119-201) builds the TLS config, reads the cert directory, pings the notary /v2/ endpoint, and sets up token/basic auth - any of those failing yields this wrap.

Solutions

  1. Verify DOCKER_CONTENT_TRUST_SERVER is a valid https URL and reachable: curl -vk <server>/v2/ should return 200 or 401.
  2. For a private notary with a self-signed cert, place the CA cert at ~/.docker/tls/<host>/ca.crt (and client.crt/client.key if mTLS) and retry.
  3. Re-authenticate to the registry: docker login <registry> so the token handler has valid credentials.
  4. Check network/proxy: ensure HTTPS_PROXY/HTTP_PROXY allow traffic to the notary server and DNS resolves the host.
  5. If repoInfo.Index.Secure is false, the client skips TLS verification (InsecureSkipVerify) - confirm that is intentional rather than masking a cert problem.

Example fix

# before: self-signed notary cert, connection fails
export DOCKER_CONTENT_TRUST_SERVER=https://notary.internal:4443
DOCKER_CONTENT_TRUST=1 docker push registry.internal/img:tag
# after: install the CA so TLS verifies
mkdir -p ~/.docker/tls/notary.internal:4443
cp /etc/notary/root-ca.crt ~/.docker/tls/notary.internal:4443/ca.crt
DOCKER_CONTENT_TRUST=1 docker push registry.internal/img:tag
Defensive patterns

Strategy: try-catch

Validate before calling

// Validate notary server reachability and TLS before the real push.
func preflightNotaryServer(server string, authCfg *registrytypes.AuthConfig) error {
    if server == "" {
        return errors.New("DOCKER_CONTENT_TRUST_SERVER is empty")
    }
    u, err := url.Parse(server)
    if err != nil || u.Scheme != "https" {
        return fmt.Errorf("trust server must be https, got %s", server)
    }
    client := &http.Client{Timeout: 5 * time.Second}
    req, _ := http.NewRequest(http.MethodGet, server+"/v2/", nil)
    if authCfg.Username != "" {
        req.SetBasicAuth(authCfg.Username, authCfg.Password)
    }
    resp, err := client.Do(req)
    if err != nil {
        return fmt.Errorf("cannot reach notary server %s: %w", server, err)
    }
    resp.Body.Close()
    return nil
}

Try / catch

repo, err := trust.GetNotaryRepository(in, out, ua, repoInfo, authCfg, "push", "pull")
if err != nil {
    return fmt.Errorf("error establishing connection to trust repository: %w", err)
}

Prevention

When it happens

Trigger: The /v2/ ping to the notary server fails or the challenge manager cannot parse the response; TLS handshake fails because the server cert is untrusted or the local tls/<host> cert directory has bad certs; DOCKER_CONTENT_TRUST_SERVER is set to a non-https URL (rejected by Server()); registry auth credentials are missing so the token handler cannot authenticate; certificateDirectory url.Parse fails.

Common situations: Self-hosted notary server with a self-signed cert that is not installed under ~/.docker/tls/<host>; DOCKER_CONTENT_TRUST_SERVER typo or http:// (must be https); behind a corporate proxy that blocks the notary endpoint; 'docker login' credentials expired so token auth returns 401; clock skew invalidating TLS; DNS resolution failure for the notary host.

Related errors


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

Appendix: source

Thrown at cmd/docker-trust/internal/trust/trust_push.go:104

	}

	if err := jsonstream.Display(ctx, in, ioStreams.Out(), jsonstream.WithAuxCallback(handleTarget)); err != nil {
		return err
	}

	if cnt > 1 {
		return errors.New("internal error: only one call to handleTarget expected")
	}

	if notaryTarget == nil {
		return errors.New("no targets found, provide a specific tag in order to sign it")
	}

	_, _ = fmt.Fprintln(ioStreams.Out(), "Signing and pushing trust metadata")

	repo, err := GetNotaryRepository(ioStreams.In(), ioStreams.Out(), userAgent, repoInfo, &authConfig, "push", "pull")
	if err != nil {
		return fmt.Errorf("error establishing connection to trust repository: %w", err)
	}

	// get the latest repository metadata so we can figure out which roles to sign
	_, err = repo.ListTargets()

	switch err.(type) {
	case client.ErrRepoNotInitialized, client.ErrRepositoryNotExist:
		keys := repo.GetCryptoService().ListKeys(data.CanonicalRootRole)
		var rootKeyID string
		// always select the first root key
		if len(keys) > 0 {
			sort.Strings(keys)
			rootKeyID = keys[0]
		} else {
			rootPublicKey, err := repo.GetCryptoService().Create(data.CanonicalRootRole, "", data.ECDSAKey)
			if err != nil {
				return err
			}

View on GitHub (pinned to 4f84911bfe)