skip to Main Content

I am experiencing an issue “Error: Cannot perform an interactive login from a non TTY device” in a GitLab CI/CD pipeline. The pipeline has four stages build, test, review, and deploy, however, “$ docker login -u $REGISTRY_USER -p $REGISTRY_PASSWORD $CI_REGISTRY” works fine for ‘stage: build’, but fails for ‘stage: deploy’. Found this article so the ‘master’ branch is protected, but did not help.

build_job:
   stage: build
   image: docker:20.10.16
   services:
     - name: docker:20.10.16-dind
       alias: docker
   variables:
     #CONTAINER_TEST_IMAGE: $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG
     DOCKER_HOST: tcp://docker:2375
     DOCKER_DRIVER: overlay2
     DOCKER_TLS_CERTDIR: ""
   script:
     - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
     - docker build -t $CONTAINER_TEST_IMAGE .
     - docker push $CONTAINER_TEST_IMAGE


# LOGS: 
$ docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
WARNING! Using --password via the CLI is insecure. Use --password-stdin.
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store
Login Succeeded
deploy_job:
  stage: deploy
  image: docker:20.10.16
  services:
    - name: docker:20.10.16-dind
      alias: docker
  variables:
    #CONTAINER_RELEASE_IMAGE: $CI_REGISTRY_IMAGE:latest
    DOCKER_HOST: tcp://docker:2375
    DOCKER_DRIVER: overlay2
    DOCKER_TLS_CERTDIR: ""
  script:
    - docker login -u $REGISTRY_USER -p $REGISTRY_PASSWORD $CI_REGISTRY
    - docker run -d -p 3000:3000 $CONTAINER_RELEASE_IMAGE
  environment: 
    name: production/$CI_COMMIT_REF_SLUG
    url: https://$CI_ENVIRONMENT_SLUG.example.com


#LOGS:
$ docker login -u $REGISTRY_USER -p $REGISTRY_PASSWORD $CI_REGISTRY
Error: Cannot perform an interactive login from a non TTY device
Cleaning up project directory and file based variables
00:00
ERROR: Job failed: exit code 1

Any help, please?
Thanks!

2

Answers


  1. Chosen as BEST ANSWER

    Following the @hakre explanation here above, the solution leads me to two subsequent errors, however, it helped me solve the "Error: Cannot perform an interactive login from a non TTY device".

    First, by adding the following command in the pipeline:

    $ echo '$REGISTRY_PASSWORD' | docker login --password-stdin -u '$REGISTRY_USER' -- '$CI_REGISTRY'
    

    It started throwing the error:

    Error response from daemon: Get "https://$CI_REGISTRY/v2/": dial tcp: lookup $CI_REGISTRY: no such host
    ERROR: Job failed: exit code 1
    

    So, modified the command to:

    $ echo '$REGISTRY_PASSWORD' | docker login --password-stdin -u '$REGISTRY_USER' https://gitlab.com
    

    In which started throwing the following error:

    Error response from daemon: Get "https://gitlab.com": unauthorized: HTTP Basic: Access denied. The provided password or token is incorrect or your account has 2FA enabled and you must use a personal access token instead of a password.
    ERROR: Job failed: exit code 1
    

    Thus, created a personal access token, which solved the issue:

    $ docker login -u <username> -p <personal_access_token> $CI_REGISTRY
    Login Succeeded
    

  2. TLDR: Provide the right credentials, otherwise the error message might not tell you what went wrong.

    Upfront summary of recommendations:

    1. Always quote the variables 1, otherwise it is easy to miss if they are unset.
    2. Provide the password via standard input (stdin), this is a better fit for CI/CD pipelines.

    The "Error: Cannot perform an interactive login from a non TTY device" emitted by the docker(1) command for a command like yours in the gitlab job:

    docker login -u $REGISTRY_USER -p $REGISTRY_PASSWORD $CI_REGISTRY
    

    The message is a bit misleading because docker login is quite lax here. Even you specified to read the password as string from the command-line (-p or --password option), if the password is missing or wrong, docker login will ask for it.

    As this makes no sense within a gitlab CI automation – there is no interactive terminal (TTY) – the docker login command is at least clever enough to realize that and quits with the bespoken error message.

    So if you get that error, you were not able to properly provide the password.

    The Missing Credentials Docker Login Situation in Gitlab CI/CD

    You can change the docker login command to make it a bit more robust, especially within CI runs.

    Let’s shortly review the usage and better understand the problem to then make some suggestions how to improve. From docker login --help:

    Usage:  docker login [OPTIONS] [SERVER]
    
    Log in to a registry.
    If no server is specified, the default is defined by the daemon.
    
    Options:
      -p, --password string   Password
          --password-stdin    Take the password from stdin
      -u, --username string   Username
    
    

    Given your original command-line:

    docker login -u $REGISTRY_USER -p $REGISTRY_PASSWORD $CI_REGISTRY
    

    and considering an error and all those three Gitlab CI/CD variables are empty, the command-line would look like the following:

    docker login -u -p
    

    That is login with the username "-p" to the default server.

    You can simulate that on your own shell by running this command with standard-input closed:

    $ 0<&- docker login -u -p
    Error: Cannot perform an interactive login from a non TTY device
    

    Exactly that error message.

    Always quote "$VARIABLES"

    Looking closer at the actual command-line, the error message is a reminder to always quote the variables1. Also for explicitness use the options delimiter --:

    docker login -u "$REGISTRY_USER" -p "$REGISTRY_PASSWORD" -- "$CI_REGISTRY"
    

    In the error case those variables are empty the command then is:

    docker login -u "" -p "" -- ""
    

    The behaviour is still the same thought, the docker login command still tries hard, and it’s not yet giving a good message.

    NOTE: It’s not solving any of the problems incl. the messaging but we at least handle the case of empty or undefined variables, thanks to the quoting they do not disappear any longer:

    0<&- docker login -u "" -p "" -- ""
    Error: Cannot perform an interactive login from a non TTY device
    

    The --password-stdin option

    Therefore within a non-interactive session (like the gitlab-runner) it is strongly recommended:

    Use the --password-stdin option. Not only to prevent the warning in the case of a successful login but to make docker login to actually complain about the empty username in the first place! Also it allows to specify it before the username argument option to remove another ambiguity:

    echo "$REGISTRY_PASSWORD" | docker login --password-stdin -u "$REGISTRY_USER" -- "$CI_REGISTRY"
    

    Now even if the variables are missing, the command still fails in a good way:

    echo "" | docker login --password-stdin -u "" -- ""
    Must provide --username with --password-stdin
    
    1. Always quote the variables 1, otherwise it is easy to miss if they are unset.
    2. Provide the password via standard input (stdin), this is a better fit for CI/CD pipelines.

    Remarks:

    1. An earlier version of the answer suggested to quote the variables with single-quotes ('), which turned out to be wrong after Franks’ answer with the final conclusion. Better than single-quotes for this Gitlab CI job with a Linux/Unix (shell) script, the variables need to be quoted with double quotes (") instead, as they are substituted by the shell and not – as assumed earlier – when the shell script is generated by the runner for its executor. Under that wrong impression I had considered single-quotes a better fit as their content won’t be substituted by the shell then, but substituting within the shell is much better now (and much more stable/safe by the gitlab runner to do it this way now as I think about it).
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search