GitHub Actions docker/login-action "Username and password required"
docker/login-action needs both a username and a password (or token). When a referenced secret is empty or misnamed, the action receives a blank value and refuses to attempt the login.
What this error means
A docker/login-action step fails immediately stating that a username and password are required, before contacting the registry.
Error: Username and password requiredDiagnose it: what token do you actually have?
Permission failures in Actions are almost never about your repository settings alone. Three things combine: the default GITHUB_TOKEN permission set for the repo or organization, the permissions: block in the workflow, and whether the event is a fork pull request, which downgrades the token to read-only regardless of everything else.
- name: Show the token scopes actually granted
run: |
curl -sI -H "Authorization: Bearer $GITHUB_TOKEN" \
https://api.github.com/ | grep -i "^x-oauth-scopes\|^x-accepted"
echo "event: ${{ github.event_name }}"
echo "fork PR: ${{ github.event.pull_request.head.repo.fork }}"
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}Common causes
Secret unset or misnamed
A password mapped to a secret that does not exist resolves to an empty string, which the action rejects.
Secret not available to the context
Secrets are not passed to workflows triggered by forked pull_request events, so the value is empty there.
How to fix it
Supply non-empty credentials
- Confirm the secret name matches exactly and the secret has a value.
- For GHCR, use github.actor and secrets.GITHUB_TOKEN.
- Skip or gate the login on forked PRs where secrets are unavailable.
- uses: docker/login-action@v3
with:
registry: docker.io
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}Grant the narrowest permission that works
Declaring a permissions: block switches the job from the repository default to exactly what you list, so an incomplete block is a common cause of a new failure right after someone tightened security. List every scope the job needs, not just the one that failed.
permissions:
contents: read # checkout
packages: write # push to GHCR
id-token: write # OIDC to a cloud provider
pull-requests: write # comment on or label a PR
checks: write # publish check runsHow to prevent it
- Double-check secret names against repository/organization settings.
- Guard registry login steps so forked PRs without secrets do not run them.