docker/cli · error

login attempt to failed with status

Error message

login attempt to %s failed with status: %d %s

What it means

Returned by loginV2 when the registry `/v2/` GET (with auth handlers attached) does not return HTTP 200. The endpoint URL, numeric status, and http.StatusText are interpolated. It signals that authentication against the registry endpoint failed (401, 403, 5xx, etc.).

Solutions

  1. Verify credentials and the registry server address are correct.
  2. Check the exact status code in the message: 401/403 -> credentials, 5xx -> registry side, 429 -> rate limit.
  3. Ensure you are reaching the intended endpoint (not a proxy/login portal).
  4. For Docker Hub, confirm the PAT has the needed scopes / account is in good standing.

Example fix

# before (wrong token)
echo $WRONG_TOKEN | docker login registry.example.com -u user --password-stdin
# login attempt to https://registry.example.com/v2/ failed with status: 401 Unauthorized
# after: use correct PAT
echo $CORRECT_PAT | docker login registry.example.com -u user --password-stdin
Defensive patterns

Strategy: try-catch

Validate before calling

// pre-flight: ensure the endpoint answers before full login
if _, err := registry.PingV2Registry(endpoint, transport); err != nil { return err }

Try / catch

if errdefs.IsUnauthorized(err) { /* prompt for correct creds */ }
if errdefs.IsUnavailable(err) { /* registry-side, retry later */ }

Prevention

When it happens

Trigger: Calling registry.Auth (docker login to a registry) whose endpoint responds with a non-200 to the authenticated /v2/ probe — bad credentials, insufficient privileges, registry down, or wrong endpoint.

Common situations: Wrong password/token; account disabled; private registry returning 401; registry behind a proxy returning 502/503; using a PAT where the registry wants username/password; rate-limited (429).

Related errors


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

Appendix: source

Thrown at internal/registry/auth.go:70

		credentialAuthConfig = *authConfig
		creds                = loginCredentialStore{authConfig: &credentialAuthConfig}
	)

	loginClient, err := v2AuthHTTPClient(endpoint.URL, authTrans, modifiers, creds, nil)
	if err != nil {
		return "", err
	}

	resp, err := loginClient.Do(req)
	if err != nil {
		err = translateV2AuthError(err)
		return "", err
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		// TODO(dmcgowan): Attempt to further interpret result, status code and error code string
		return "", fmt.Errorf("login attempt to %s failed with status: %d %s", endpointStr, resp.StatusCode, http.StatusText(resp.StatusCode))
	}

	return credentialAuthConfig.IdentityToken, nil
}

func v2AuthHTTPClient(endpoint *url.URL, authTransport http.RoundTripper, modifiers []transport.RequestModifier, creds auth.CredentialStore, scopes []auth.Scope) (*http.Client, error) {
	challengeManager, err := PingV2Registry(endpoint, authTransport)
	if err != nil {
		return nil, err
	}

	authHandlers := []auth.AuthenticationHandler{
		auth.NewTokenHandlerWithOptions(auth.TokenHandlerOptions{
			Transport:     authTransport,
			Credentials:   creds,
			OfflineAccess: true,
			ClientID:      AuthClientID,
			Scopes:        scopes,

View on GitHub (pinned to 4f84911bfe)