The 'terminal prompts disabled' error occurs when Git needs to prompt for credentials but runs in a non-interactive environment. This commonly happens in CI/CD pipelines, scripts, or automated processes where there's no terminal to receive user input.
This error indicates that Git attempted to authenticate with a remote repository but couldn't prompt for credentials because terminal prompts have been disabled. Git sets the environment variable `GIT_TERMINAL_PROMPT=0` automatically in certain contexts, or you may have set it manually. When Git needs credentials to access a repository over HTTPS and no cached credentials are available, it normally prompts for a username and password. However, in non-interactive environments like: - CI/CD pipelines (GitHub Actions, GitLab CI, Jenkins, etc.) - Scripts running without a TTY - Docker builds - Cron jobs - Background processes Git cannot display a prompt or read user input, so it fails with this error instead of hanging indefinitely waiting for input that will never come. The error specifically tells you Git tried to read a "Username" but couldn't because it had no way to ask you for it. This is a safety feature - without it, automated processes would hang forever waiting for credentials.
The most common solution for CI/CD pipelines is to use a Personal Access Token (PAT) embedded in the repository URL or provided via environment variables.
Method 1: URL with embedded token (GitHub Actions example):
# In your workflow file
steps:
- name: Clone private repo
run: |
git clone https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/owner/repo.gitMethod 2: Configure Git to use token for all HTTPS requests:
# Set up credential helper with token
git config --global credential.helper '!f() { echo "password=${GH_TOKEN}"; }; f'
# Or use the URL directly
git config --global url."https://${GH_TOKEN}@github.com/".insteadOf "https://github.com/"For GitHub Actions specifically:
- name: Checkout with token
uses: actions/checkout@v4
with:
token: ${{ secrets.PAT_TOKEN }}
submodules: recursiveGenerate a PAT on GitHub:
1. Go to Settings > Developer settings > Personal access tokens
2. Generate new token with repo scope
3. Add it as a secret in your CI/CD system
SSH keys don't require terminal prompts, making them ideal for automated environments.
Step 1: Generate a deploy key (for CI/CD):
ssh-keygen -t ed25519 -C "[email protected]" -f ./deploy_key -N ""Step 2: Add public key to GitHub repository:
1. Go to repository Settings > Deploy keys
2. Add the contents of deploy_key.pub
3. Enable "Allow write access" if pushing is needed
Step 3: Configure CI/CD to use the key:
# GitHub Actions example
steps:
- name: Setup SSH
run: |
mkdir -p ~/.ssh
echo "${{ secrets.DEPLOY_KEY }}" > ~/.ssh/id_ed25519
chmod 600 ~/.ssh/id_ed25519
ssh-keyscan github.com >> ~/.ssh/known_hosts
- name: Clone via SSH
run: git clone [email protected]:owner/repo.gitFor GitLab CI:
before_script:
- eval $(ssh-agent -s)
- echo "$SSH_PRIVATE_KEY" | ssh-add -
- mkdir -p ~/.ssh && chmod 700 ~/.ssh
- ssh-keyscan gitlab.com >> ~/.ssh/known_hostsWhen running Git in scripts, pre-configure credentials before any git commands run.
Using git credential fill:
#!/bin/bash
# Pre-fill credentials before git commands
echo "protocol=https
host=github.com
username=${GIT_USERNAME}
password=${GIT_TOKEN}" | git credential approve
# Now git commands will use these credentials
git clone https://github.com/owner/private-repo.gitUsing .netrc file (Unix/Linux/macOS):
# Create or update ~/.netrc
cat > ~/.netrc << EOF
machine github.com
login ${GIT_USERNAME}
password ${GIT_TOKEN}
EOF
chmod 600 ~/.netrc
# Git will automatically use .netrc for authentication
git clone https://github.com/owner/repo.gitUsing Git askpass helper:
# Create a helper script
echo '#!/bin/bash
echo "${GIT_PASSWORD}"' > /tmp/git-askpass.sh
chmod +x /tmp/git-askpass.sh
# Set environment variables
export GIT_ASKPASS=/tmp/git-askpass.sh
export GIT_PASSWORD="your-token-here"
# Git will now use the askpass script instead of prompting
git clone https://github.com/owner/repo.gitDocker builds are non-interactive by default. Here's how to handle git authentication:
Method 1: Build arguments with token:
# Dockerfile
ARG GIT_TOKEN
RUN git config --global url."https://${GIT_TOKEN}@github.com/".insteadOf "https://github.com/"
RUN git clone https://github.com/owner/private-repo.git# Build with token
docker build --build-arg GIT_TOKEN=$GH_TOKEN .Method 2: SSH mount (Docker BuildKit):
# syntax=docker/dockerfile:1
FROM alpine
RUN apk add --no-cache git openssh-client
RUN mkdir -p -m 0700 ~/.ssh && ssh-keyscan github.com >> ~/.ssh/known_hosts
RUN --mount=type=ssh git clone [email protected]:owner/repo.git# Build with SSH agent
DOCKER_BUILDKIT=1 docker build --ssh default .Method 3: Secret mount (Docker BuildKit):
# syntax=docker/dockerfile:1
FROM alpine
RUN apk add --no-cache git
RUN --mount=type=secret,id=gittoken \
GIT_TOKEN=$(cat /run/secrets/gittoken) && \
git clone https://x-access-token:${GIT_TOKEN}@github.com/owner/repo.gitecho "your-token" > .gittoken
DOCKER_BUILDKIT=1 docker build --secret id=gittoken,src=.gittoken .Important: Never bake tokens into image layers - use multi-stage builds or secrets.
Submodules often cause this error because each submodule may require separate authentication.
Configure submodule URLs to use tokens:
# Replace HTTPS URLs with token-embedded URLs
git config --global url."https://x-access-token:${GH_TOKEN}@github.com/".insteadOf "https://github.com/"
# Initialize and update submodules
git submodule update --init --recursiveUsing .gitmodules URL rewriting:
# In your CI script, before submodule init
git config submodule.path/to/submodule.url "https://[email protected]/owner/submodule.git"
git submodule update --initGitHub Actions with submodules:
- uses: actions/checkout@v4
with:
submodules: recursive
token: ${{ secrets.PAT_WITH_REPO_ACCESS }}Note: The default GITHUB_TOKEN only has access to the current repository. For private submodules in other repos, you need a PAT with broader access.
Convert submodules to SSH (if using SSH auth):
# In .gitmodules, change:
# url = https://github.com/owner/repo.git
# to:
# url = [email protected]:owner/repo.gitIf you're still having issues, use these commands to debug:
Check if terminal prompts are disabled:
echo $GIT_TERMINAL_PROMPT
# If this outputs "0", prompts are disabledEnable verbose Git output:
GIT_TRACE=1 GIT_CURL_VERBOSE=1 git clone https://github.com/owner/repo.gitCheck credential helper configuration:
git config --list --show-origin | grep credentialTest credential helper manually:
echo "protocol=https
host=github.com" | git credential fillVerify SSH connectivity (if using SSH):
ssh -vT [email protected]Temporarily enable prompts for testing:
# Unset the variable
unset GIT_TERMINAL_PROMPT
# Or explicitly enable
export GIT_TERMINAL_PROMPT=1Check if running in a TTY:
if [ -t 0 ]; then
echo "Running interactively"
else
echo "Running non-interactively - need pre-configured credentials"
fi### Understanding GIT_TERMINAL_PROMPT
Git automatically sets GIT_TERMINAL_PROMPT=0 in certain scenarios:
- When stdin is not a terminal (TTY)
- In some CI/CD environments
- When running as a subprocess of certain tools
You can control this behavior:
# Force disable prompts (useful for scripts that should fail fast)
export GIT_TERMINAL_PROMPT=0
# Force enable prompts
export GIT_TERMINAL_PROMPT=1### GitHub Actions Specifics
The GITHUB_TOKEN has limitations:
- Only works for the repository running the workflow
- Cannot access other private repositories
- Cannot trigger other workflows
For accessing multiple repos, create a PAT:
1. Use fine-grained tokens for specific repositories
2. Or classic tokens with repo scope for broader access
# Using PAT for multiple repo access
env:
GH_TOKEN: ${{ secrets.PAT_TOKEN }}
steps:
- run: |
git config --global url."https://x-access-token:${GH_TOKEN}@github.com/".insteadOf "https://github.com/"### GitLab CI Specifics
GitLab provides CI_JOB_TOKEN automatically:
script:
- git clone https://gitlab-ci-token:${CI_JOB_TOKEN}@gitlab.com/group/project.gitFor cross-project access, use deploy tokens or personal access tokens stored in CI/CD variables.
### Jenkins Pipeline
pipeline {
agent any
environment {
GIT_CREDENTIALS = credentials('git-credentials-id')
}
stages {
stage('Clone') {
steps {
sh '''
git config --global credential.helper '!f() { echo "password=${GIT_CREDENTIALS_PSW}"; }; f'
git clone https://${GIT_CREDENTIALS_USR}@github.com/owner/repo.git
'''
}
}
}
}### Security Best Practices
1. Never commit tokens to repositories - Use CI/CD secrets
2. Use short-lived tokens - Set expiration dates
3. Principle of least privilege - Only grant necessary scopes
4. Rotate tokens regularly - Especially after any potential exposure
5. Use deploy keys for single-repo access - More secure than PATs
6. Consider GitHub App tokens - More granular and auditable
### Troubleshooting Hanging Git Commands
If git hangs instead of failing (prompts not properly disabled):
# Set timeout for git operations
timeout 60 git clone https://github.com/owner/repo.git
# Or with environment variable
export GIT_TERMINAL_PROMPT=0### Working with Git LFS
Git LFS also respects terminal prompts settings:
# Configure LFS to use the same credentials
git config --global lfs.https://github.com/.access basic
git config --global credential.helper '!f() { echo "password=${GH_TOKEN}"; }; f'kex_exchange_identification: Connection closed by remote host
Connection closed by remote host when connecting to Git server
fatal: unable to access: Proxy auto-configuration failed
How to fix 'Proxy auto-configuration failed' in Git
fatal: unable to access: Authentication failed (proxy requires basic auth)
How to fix 'Authentication failed (proxy requires basic auth)' in Git
fatal: unable to access: no_proxy configuration not working
How to fix 'no_proxy configuration not working' in Git
fatal: unable to read tree object in treeless clone
How to fix 'unable to read tree object in treeless clone' in Git