docker/cli · error
error: cannot perform an interactive login from a non-TTY…
Error message
error: cannot perform an interactive login from a non-TTY device
What it means
Thrown by loginUser when either the username or password is missing AND stdin is not a TTY. Without an interactive terminal the CLI cannot prompt for the missing credential, so it refuses rather than hang. This is the classic non-interactive/CI login failure.
Solutions
- Provide both credentials non-interactively: 'printf %s "$TOKEN" | docker login -u <user> --password-stdin'.
- Run the command in a real interactive TTY if you want prompting.
- Use a credential helper or stored credentials to avoid passing secrets at all.
Example fix
# before (in CI) echo "$TOKEN" | docker login # after printf '%s' "$TOKEN" | docker login -u "$DOCKER_USER" --password-stdin
Defensive patterns
Strategy: validation
Validate before calling
// Detect non-TTY stdin and require explicit credentials
if (user == "" || password == "") && !in.IsTerminal() {
return fmt.Errorf("non-interactive login requires -u and --password-stdin")
} Prevention
- In CI always pass -u and --password-stdin together.
- Detect TTY availability in wrappers and fail with a clear message.
- Use credential helpers to avoid passing secrets on the command line.
When it happens
Trigger: Running 'echo token | docker login' (no -u/-p) in a script or CI; 'cat file | docker login'; running under mintty/Git Bash where stdin is a pipe not a console (login.go lines 237-238).
Common situations: CI pipelines, cron jobs, non-interactive SSH sessions, Windows mintty/Git Bash pipes, any redirected stdin.
Related errors
- error: username is required
- error: password is required
- conflicting options: cannot specify both --password and…
- the --password-stdin option requires --username to be set
- username is empty
AI-assisted analysis of docker/cli@4f84911bfe (2026-08-07).
Data as JSON: /api/errors/e1467774b72a1ab7.
Report an issue: GitHub.
Appendix: source
Thrown at cli/command/registry/login.go:238
}
if err := storeCredentials(dockerCLI.ConfigFile(), authConfig); err != nil {
return "", err
}
return resp.Auth.Status, err
}
func loginUser(ctx context.Context, dockerCLI command.Cli, opts loginOptions, defaultUsername, serverAddress string) (msg string, _ error) {
// Some links documenting this:
// - https://code.google.com/archive/p/mintty/issues/56
// - https://github.com/docker/docker/issues/15272
// - https://mintty.github.io/ (compatibility)
// Linux will hit this if you attempt `cat | docker login`, and Windows
// will hit this if you attempt docker login from mintty where stdin
// is a pipe, not a character based console.
if (opts.user == "" || opts.password == "") && !dockerCLI.In().IsTerminal() {
return "", errors.New("error: cannot perform an interactive login from a non-TTY device")
}
// If we're logging into the index server and the user didn't provide a username or password, use the device flow
if serverAddress == registry.IndexServer && opts.user == "" && opts.password == "" {
var err error
msg, err = loginWithDeviceCodeFlow(ctx, dockerCLI)
// if the error represents a failure to initiate the device-code flow,
// then we fallback to regular cli credentials login
if !errors.Is(err, manager.ErrDeviceLoginStartFail) {
return msg, err
}
_, _ = fmt.Fprint(dockerCLI.Err(), "Failed to start web-based login - falling back to command line login...\n\n")
}
return loginWithUsernameAndPassword(ctx, dockerCLI, opts, defaultUsername, serverAddress)
}
func loginWithUsernameAndPassword(ctx context.Context, dockerCLI command.Cli, opts loginOptions, defaultUsername, serverAddress string) (msg string, _ error) {View on GitHub (pinned to 4f84911bfe)