{"record":{"id":"8229dc91c27b85ec","repo":"docker/cli","slug":"failed-to-start-device-code-flow-login","errorCode":null,"errorMessage":"failed to start device code flow login","messagePattern":"failed to start device code flow login","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/oauth/manager/manager.go","lineNumber":76,"sourceCode":"\t\tbrowser.Stderr = io.Discard\n\t\topenBrowser = browser.OpenURL\n\t}\n\n\treturn &OAuthManager{\n\t\tclientID: options.ClientID,\n\t\taudience: options.Audience,\n\t\ttenant:   options.Tenant,\n\t\tstore:    options.Store,\n\t\tapi: api.API{\n\t\t\tTenantURL: \"https://\" + options.Tenant,\n\t\t\tClientID:  options.ClientID,\n\t\t\tScopes:    scopes,\n\t\t},\n\t\topenBrowser: openBrowser,\n\t}\n}\n\nvar ErrDeviceLoginStartFail = errors.New(\"failed to start device code flow login\")\n\n// LoginDevice launches the device authentication flow with the tenant,\n// printing instructions to the provided writer and attempting to open the\n// browser for the user to authenticate.\n// After the user completes the browser login, LoginDevice uses the retrieved\n// tokens to create a Hub PAT which is returned to the caller.\n// The retrieved tokens are stored in the credentials store (under a separate\n// key), and the refresh token is concatenated with the client ID.\nfunc (m *OAuthManager) LoginDevice(ctx context.Context, w io.Writer) (*types.AuthConfig, error) {\n\tstate, err := m.api.GetDeviceCode(ctx, m.audience)\n\tif err != nil {\n\t\tlogrus.Debugf(\"failed to start device code login: %v\", err)\n\t\treturn nil, ErrDeviceLoginStartFail\n\t}\n\n\tif state.UserCode == \"\" {\n\t\tlogrus.Debugf(\"failed to start device code login: missing user code\")\n\t\treturn nil, ErrDeviceLoginStartFail","sourceCodeStart":58,"sourceCodeEnd":94,"githubUrl":"https://github.com/docker/cli/blob/4f84911bfe8811e9b028e4b1fee8e7510be79387/internal/oauth/manager/manager.go#L58-L94","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before: opaque error with no detail\nauthCfg, err := mgr.LoginDevice(ctx, os.Stdout)\nif err != nil {\n    return err // 'failed to start device code flow login' — no detail\n}\n\n// after: enable debug logging to expose root cause\nlogrus.SetLevel(logrus.DebugLevel)\nauthCfg, err := mgr.LoginDevice(ctx, os.Stdout)\nif err != nil {\n    if errors.Is(err, manager.ErrDeviceLoginStartFail) {\n        // check debug logs for 'failed to start device code login: <detail>'\n        return fmt.Errorf(\"device login unavailable; check network and tenant config\")\n    }\n    return err\n}","handlingStrategy":"retry","validationCode":"// Pre-flight check before LoginDevice\nfunc canReachTenant(ctx context.Context, tenant string) error {\n    u := \"https://\" + tenant + \"/oauth/device/code\"\n    req, _ := http.NewRequestWithContext(ctx, \"POST\", u, strings.NewReader(\"\"))\n    resp, err := http.DefaultClient.Do(req)\n    if err != nil {\n        return fmt.Errorf(\"cannot reach tenant %s: %w\", tenant, err)\n    }\n    defer resp.Body.Close()\n    // Any HTTP response (even 4xx) means the tenant is reachable\n    return nil\n}","typeGuard":"// Check if the error is specifically the device-login-start sentinel\nfunc isDeviceLoginStartFail(err error) bool {\n    return errors.Is(err, manager.ErrDeviceLoginStartFail)\n}","tryCatchPattern":"authCfg, err := mgr.LoginDevice(ctx, w)\nif err != nil {\n    if errors.Is(err, manager.ErrDeviceLoginStartFail) {\n        // Enable debug logging and retry; underlying error is only in debug logs\n        logrus.SetLevel(logrus.DebugLevel)\n        return fmt.Errorf(\"device login failed to start (enable debug for details); try 'docker login -u <user>' as fallback\")\n    }\n    return err\n}","preventionTips":["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."],"tags":["oauth","authentication","login","device-flow"],"backgroundTag":null,"analyzedSha":"4f84911bfe8811e9b028e4b1fee8e7510be79387","analyzedAt":"2026-08-07T12:15:29.814Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}