Overview
Docker fails to start a container when the USER declared in the Dockerfile (or passed with --user) is not present in the final image. Typical causes:
- The base image lacks that user/group.
- You created the user in a builder stage but not in the final stage.
- You used a username with COPY --chown before creating it.
- You’re using a distroless or scratch image without /etc/passwd entries.
The fix is to ensure the user exists in the final image, or use a numeric UID/GID that does not depend on /etc/passwd.
Quickstart
- Prefer numeric UID:GID in USER and COPY --chown.
- Create the user in the final stage (not just the builder).
- For distroless/scratch, use a numeric UID (commonly 65532) and avoid name-based lookups.
Minimal working example (Alpine)
This example creates a non-root user by UID/GID, sets file ownership safely with COPY --chown, and runs a simple script.
# Dockerfile
FROM alpine:3.20
ARG UID=10001
ARG GID=10001
# Create group and user
RUN addgroup -g ${GID} app && \
adduser -D -h /home/app -u ${UID} -G app app
WORKDIR /app
COPY --chown=${UID}:${GID} app.sh /app/app.sh
RUN chmod +x /app/app.sh
# Use numeric UID:GID to avoid name lookup issues
USER ${UID}:${GID}
ENTRYPOINT ["/app/app.sh"]
# app.sh
#!/bin/sh
id
whoami || echo "no username for this UID"
echo "App running as non-root"
sleep 1
Build and run:
docker build -t demo-nonroot .
docker run --rm demo-nonroot
Diagnose the error
- Inspect the image’s configured user:
docker inspect --format='{{.Config.User}}' IMAGE - Override the user for debugging and check /etc/passwd and /etc/group:
docker run --rm --user root -it IMAGE sh -lc 'cat /etc/passwd; cat /etc/group' - If multi-stage is used, verify the user is created in the final stage (the last FROM).
- If COPY --chown is used, ensure the user/group exists before that instruction.
Common fixes
Create the user in the final stage with a stable UID/GID:
FROM debian:stable-slim ARG UID=10001 ARG GID=10001 RUN groupadd -g ${GID} app && \ useradd -r -u ${UID} -g app -d /home/app -m app USER ${UID}:${GID}Use numeric IDs everywhere:
USER 10001:10001 COPY --chown=10001:10001 . /appMulti-stage: don’t create the user only in the builder. Either recreate it in the final stage or copy entries:
FROM debian:stable-slim AS builder RUN groupadd -g 10001 app && useradd -r -u 10001 -g app app FROM debian:stable-slim # Option A: re-create RUN groupadd -g 10001 app && useradd -r -u 10001 -g app app # Option B: copy passwd/group lines (same distro family) COPY --from=builder /etc/passwd /etc/passwd COPY --from=builder /etc/group /etc/group USER 10001:10001Distroless/scratch: rely on numeric UID; do not assume /etc/passwd exists.
FROM gcr.io/distroless/static:nonroot # Many distroless images include UID 65532 ("nonroot"). Prefer numeric UID. USER 65532 ENTRYPOINT ["/app/my-static-binary"]
Platform-specific user creation
| Base image | Create group | Create user |
|---|---|---|
| Debian/Ubuntu | groupadd -g G app | useradd -r -u U -g app -d /home/app -m app |
| Alpine | addgroup -g G app | adduser -D -h /home/app -u U -G app app |
| BusyBox | addgroup -g G app | adduser -D -H -u U -G app app |
| Distroless | n/a (no package manager) | Use numeric UID (e.g., USER 65532) |
U = desired UID, G = desired GID.
Example of a broken Dockerfile and fix
Broken: user is referenced but never created.
FROM alpine:3.20
USER app
ENTRYPOINT ["id"]
Run:
docker build -t broken . && docker run --rm broken
# error: user app not found
Fixed: create the user first and use numeric UID:GID.
FROM alpine:3.20
RUN addgroup -g 10001 app && adduser -D -h /home/app -u 10001 -G app app
USER 10001:10001
ENTRYPOINT ["id"]
Permissions and Kubernetes note
If you set runAsUser/runAsGroup in Kubernetes, the container still needs file permissions that match that UID/GID. Ensure volumes and working directories are writable by that UID:
# fragment
securityContext:
runAsUser: 10001
runAsGroup: 10001
fsGroup: 10001
Pre-chown mounted paths or set appropriate permissions during image build.
Pitfalls
- Creating the user in the builder stage only. The final stage won’t have it.
- Using a username in USER or COPY --chown before creating it.
- Assuming /etc/passwd exists (distroless, scratch). Use numeric UID.
- Inconsistent UID/GID across environments causing permission mismatches on mounted volumes.
- Relying on whoami; it fails without an /etc/passwd entry. Use id instead.
Performance notes
- Prefer COPY --chown over a subsequent RUN chown -R; it avoids an extra layer and reduces I/O.
- Create users with fixed UID/GID to avoid expensive recursive chown on startup.
- Minimize file ownership changes by structuring COPY steps so that ownership is set during copy, not after.
- Avoid installing user-management packages in final images; create users with base tooling or numeric UID when possible to keep images small.
Tiny FAQ
- Can I just use USER root to avoid the error?
- Yes, but it reduces security. Prefer a non-root UID/GID.
- Do I need /etc/passwd for USER to work?
- No if you use numeric UID:GID. Names require /etc/passwd and /etc/group entries.
- What UID should I use for distroless?
- Many images ship with UID 65532. Use USER 65532, or consult the image metadata.
- How do I debug a failing image?
- Override the user: docker run --user root -it IMAGE sh, then inspect passwd/group and permissions.