docker/cli ยท error

error: cannot perform an interactive login from a non-TTY de

Error message

error: cannot perform an interactive login from a non-TTY device

What it means

Raised by loginUser (cli/command/registry/login.go:238) when the login needs to prompt interactively (username or password missing) but stdin is not a terminal (dockerCLI.In().IsTerminal() is false). Prompting for hidden-input credentials requires a real character device; a pipe or redirected stdin cannot support the no-echo password prompt, so the CLI fails up front. The source comments note this hits `cat | docker login` on Linux and mintty on Windows, where stdin is a pipe rather than a console.

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 e9452d6e78)

Solutions

  1. Supply full credentials non-interactively: printf '%s' "$TOKEN" | docker login -u "$USER" --password-stdin <registry>
  2. On mintty/Git Bash, run `winpty docker login` or use a console with real TTY semantics (Windows Terminal, PowerShell, CMD)
  3. When running through ssh or docker exec, allocate a TTY (ssh -t, docker exec -it) if interactive login is genuinely wanted

Example fix

# before (CI, no TTY)
docker login registry.example.com

# after
printf '%s' "$REGISTRY_TOKEN" | docker login -u "$REGISTRY_USER" --password-stdin registry.example.com

When it happens

Trigger: Running docker login with incomplete credentials (missing -u or password) in any non-TTY context: piped stdin (cat creds | docker login without --password-stdin), CI jobs, cron, docker exec without -t, ssh without -t, Git Bash/mintty/MSYS on Windows where stdin is emulated as a pipe.

Common situations: CI pipelines calling bare `docker login` expecting prompts; Windows users on mintty/Git Bash hitting this even in an apparently interactive shell (fix: prefix with winpty or use Windows Terminal); scripts that pipe the password on stdin but forget --password-stdin, so the CLI still thinks it must prompt.

Related errors


AI-assisted analysis of docker/cli@e9452d6e78 (2026-08-01). Data as JSON: /data/errors/e1467774b72a1ab7.json. Report an issue: GitHub.