docker/cli · error
failed to start device code flow login
Error message
failed to start device code flow login
What it means
ErrDeviceLoginStartFail (internal/oauth/manager/manager.go:76) is returned by LoginDevice when the initial call to GetDeviceCode fails for any reason, or when the tenant response is missing the UserCode field. The actual underlying error is only logged at debug level via logrus.Debugf and is not exposed to the caller, making this a deliberately opaque sentinel error.
Solutions
- Enable debug logging (DOCKER_CLI_DEBUG=1 or logrus debug level) to see the underlying GetDeviceCode error printed alongside 'failed to start device code login'.
- Verify network connectivity to the tenant URL: ensure DNS resolves and the host is reachable on port 443.
- Check that ClientID, Audience, and Tenant in OAuthManagerOptions are correctly configured for your Auth0 application.
- Fall back to token-based login (docker login -u <username>) if the device-code flow endpoint is unavailable.
Example fix
// before: opaque error with no detail
authCfg, err := mgr.LoginDevice(ctx, os.Stdout)
if err != nil {
return err // 'failed to start device code flow login' — no detail
}
// after: enable debug logging to expose root cause
logrus.SetLevel(logrus.DebugLevel)
authCfg, err := mgr.LoginDevice(ctx, os.Stdout)
if err != nil {
if errors.Is(err, manager.ErrDeviceLoginStartFail) {
// check debug logs for 'failed to start device code login: <detail>'
return fmt.Errorf("device login unavailable; check network and tenant config")
}
return err
} Defensive patterns
Strategy: retry
Validate before calling
// Pre-flight check before LoginDevice
func canReachTenant(ctx context.Context, tenant string) error {
u := "https://" + tenant + "/oauth/device/code"
req, _ := http.NewRequestWithContext(ctx, "POST", u, strings.NewReader(""))
resp, err := http.DefaultClient.Do(req)
if err != nil {
return fmt.Errorf("cannot reach tenant %s: %w", tenant, err)
}
defer resp.Body.Close()
// Any HTTP response (even 4xx) means the tenant is reachable
return nil
} Type guard
// Check if the error is specifically the device-login-start sentinel
func isDeviceLoginStartFail(err error) bool {
return errors.Is(err, manager.ErrDeviceLoginStartFail)
} Try / catch
authCfg, err := mgr.LoginDevice(ctx, w)
if err != nil {
if errors.Is(err, manager.ErrDeviceLoginStartFail) {
// Enable debug logging and retry; underlying error is only in debug logs
logrus.SetLevel(logrus.DebugLevel)
return fmt.Errorf("device login failed to start (enable debug for details); try 'docker login -u <user>' as fallback")
}
return err
} Prevention
- Enable debug logging (logrus debug level) before calling LoginDevice so the underlying GetDeviceCode error is visible.
- Verify network connectivity and ClientID/Audience/Tenant configuration at startup.
- Provide a fallback to username/password login when the device-code flow is unavailable.
- Validate DNS resolution of the tenant hostname before attempting login.
When it happens
Trigger: LoginDevice calls m.api.GetDeviceCode(ctx, m.audience) which returns an error (network failure, DNS resolution failure, TLS error, HTTP error from tenant), OR GetDeviceCode succeeds but state.UserCode is an empty string. In both cases the sentinel ErrDeviceLoginStartFail is returned.
Common situations: No network connectivity to the Auth0 tenant host, wrong ClientID or Audience configured, tenant URL unreachable behind a firewall, clock skew causing TLS handshake failure, or a tenant misconfiguration that returns a device-code response without a user_code field.
Related errors
- timed out waiting for device token
- unexpected response from tenant
- login canceled
- failed to get tokens
- failed to decode response
AI-assisted analysis of docker/cli@4f84911bfe (2026-08-07).
Data as JSON: /api/errors/8229dc91c27b85ec.
Report an issue: GitHub.
Appendix: source
Thrown at internal/oauth/manager/manager.go:76
browser.Stderr = io.Discard
openBrowser = browser.OpenURL
}
return &OAuthManager{
clientID: options.ClientID,
audience: options.Audience,
tenant: options.Tenant,
store: options.Store,
api: api.API{
TenantURL: "https://" + options.Tenant,
ClientID: options.ClientID,
Scopes: scopes,
},
openBrowser: openBrowser,
}
}
var ErrDeviceLoginStartFail = errors.New("failed to start device code flow login")
// LoginDevice launches the device authentication flow with the tenant,
// printing instructions to the provided writer and attempting to open the
// browser for the user to authenticate.
// After the user completes the browser login, LoginDevice uses the retrieved
// tokens to create a Hub PAT which is returned to the caller.
// The retrieved tokens are stored in the credentials store (under a separate
// key), and the refresh token is concatenated with the client ID.
func (m *OAuthManager) LoginDevice(ctx context.Context, w io.Writer) (*types.AuthConfig, error) {
state, err := m.api.GetDeviceCode(ctx, m.audience)
if err != nil {
logrus.Debugf("failed to start device code login: %v", err)
return nil, ErrDeviceLoginStartFail
}
if state.UserCode == "" {
logrus.Debugf("failed to start device code login: missing user code")
return nil, ErrDeviceLoginStartFailView on GitHub (pinned to 4f84911bfe)