How to fix WORKDIR: cannot change directory to /app: no such file or directory in Docker

DockerBEGINNERLOWUpdated Dec 6, 2025ยท 218 views

The WORKDIR error occurs when Docker cannot change to the specified directory during a container run or build. This typically happens with multi-stage builds, incorrect base images, or when running containers with a WORKDIR that was not created. Verify your Dockerfile structure or use absolute paths.

Quick fix

Fixes WORKDIR: cannot change directory to /app: no such file or directory

# Run a shell in the image to inspect its filesystem
docker run --rm -it --entrypoint /bin/sh your-image -c "ls -la /"

# Or if the image has no shell (minimal/distroless)
docker run --rm -it alpine sh -c "docker save your-image | tar -tvf - | grep app"

# Check the image layers for the directory
docker history your-image
  1. Verify the directory exists in the final image
  2. Add explicit WORKDIR in the final stage of multi-stage builds
  3. Use absolute paths and ensure WORKDIR comes before COPY/RUN
  4. Handle scratch and distroless base images
docker โ€” error
# Run a shell in the image to inspect its filesystem
docker run --rm -it --entrypoint /bin/sh your-image -c "ls -la /"
# Or if the image has no shell (minimal/distroless)
docker run --rm -it alpine sh -c "docker save your-image | tar -tvf - | grep app"
# Check the image layers for the directory
docker history your-image
WORKDIR: cannot change directory to /app: no such file or directory

What this error means

The "WORKDIR: cannot change directory to /app: no such file or directory" error indicates that Docker is trying to set the working directory to a path that doesn't exist inside the container. This error can occur in two main scenarios: 1. **During container runtime**: When you run a container (with `docker run`) and the image specifies a WORKDIR that doesn't exist in the final image layers. 2. **During image build**: When Docker processes a WORKDIR instruction in a Dockerfile and the directory cannot be created (rare, as WORKDIR normally creates the directory automatically). The most common cause is multi-stage builds where the WORKDIR exists in a build stage but not in the final runtime stage. Docker's WORKDIR instruction should automatically create the directory if it doesn't exist, so this error typically indicates a more fundamental issue with the image structure or how the container is being run.

Typical symptoms

  • Container fails to start with 'cannot change directory' error
  • Docker run command exits immediately with WORKDIR error
  • Multi-stage build produces image that fails at runtime
  • Container works in development but fails in production with different base image
  • CI/CD pipeline fails when running container from newly built image
  • docker exec commands fail with directory not found error

Common causes

  1. Multi-stage build final stage doesn't include the WORKDIR directory
  2. Base image was changed and no longer contains expected directory structure
  3. Running container with -w flag pointing to non-existent directory (some runtimes)
  4. Image was built with scratch base and WORKDIR was never created
  5. Filesystem corruption or incomplete image layer download
  6. Using a minimal/distroless base image without shell to create directories
  7. WORKDIR path conflicts with a file that exists at that path
  8. Case sensitivity mismatch between development (macOS) and production (Linux)

How to fix "WORKDIR: cannot change directory to /app: no such file or directory"

1Verify the directory exists in the final image

First, check if the directory actually exists in your Docker image:

bash
# Run a shell in the image to inspect its filesystem
docker run --rm -it --entrypoint /bin/sh your-image -c "ls -la /"

# Or if the image has no shell (minimal/distroless)
docker run --rm -it alpine sh -c "docker save your-image | tar -tvf - | grep app"

# Check the image layers for the directory
docker history your-image

If the directory doesn't exist, you need to ensure it's created in your Dockerfile.

2Add explicit WORKDIR in the final stage of multi-stage builds

In multi-stage builds, each stage starts fresh. The WORKDIR from a build stage doesn't carry over:

dockerfile
# Build stage
FROM node:18-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build

# Runtime stage - WORKDIR must be declared again!
FROM node:18-alpine AS runtime
WORKDIR /app  # This creates /app in the final image
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
CMD ["node", "dist/index.js"]

The key insight is that WORKDIR /app in the runtime stage creates the directory - it doesn't inherit from the builder stage.

3Use absolute paths and ensure WORKDIR comes before COPY/RUN

Always use absolute paths for WORKDIR and place it early in your Dockerfile:

dockerfile
# Good practice - absolute path, declared early
FROM alpine:latest
WORKDIR /app
COPY . .
RUN chmod +x ./entrypoint.sh

# Bad practice - relative path, may inherit unknown base WORKDIR
FROM some-base-image
WORKDIR app  # Relative to whatever WORKDIR the base image set
COPY . .

Docker recommends always using absolute paths to avoid unexpected behavior from base images:

dockerfile
# Explicitly set WORKDIR even if you think the base sets it
FROM nginx:alpine
WORKDIR /usr/share/nginx/html
COPY public/ .
4Handle scratch and distroless base images

When using FROM scratch or distroless images, you need to handle directory creation differently:

dockerfile
# For scratch images, create directory structure in builder
FROM golang:1.21-alpine AS builder
WORKDIR /app
COPY . .
RUN CGO_ENABLED=0 go build -o /app/myapp

FROM scratch
# Copy the binary - WORKDIR won't work without a shell
COPY --from=builder /app/myapp /myapp
ENTRYPOINT ["/myapp"]

For distroless images that support WORKDIR:

dockerfile
FROM golang:1.21 AS builder
WORKDIR /app
COPY . .
RUN go build -o /app/server

FROM gcr.io/distroless/static-debian11
WORKDIR /app
COPY --from=builder /app/server /app/server
CMD ["/app/server"]
5Check for case sensitivity issues

If your image works on macOS but fails on Linux, check for case sensitivity issues:

bash
# macOS is case-insensitive by default
# These refer to the same directory on Mac:
# /App, /APP, /app

# Linux is case-sensitive
# /App, /APP, /app are three different directories

Ensure your Dockerfile and code use consistent casing:

dockerfile
# Ensure exact case match throughout
WORKDIR /app  # lowercase
COPY src/ ./src/  # lowercase
RUN cd /app && ./build.sh  # lowercase - must match WORKDIR

Check your local filesystem for mismatched cases:

bash
# Find files with unusual casing
find . -name "[A-Z]*" -type f
6Fix runtime -w flag issues

If you're getting this error when using docker run -w, ensure the directory exists:

bash
# This may fail if /nonexistent doesn't exist in the image
docker run -w /nonexistent alpine pwd

# Standard Docker creates the directory, but some container runtimes don't
# Check your container runtime behavior

# Safe approach: use an image WORKDIR or create the directory
docker run alpine sh -c "mkdir -p /myworkdir && cd /myworkdir && pwd"

Note: Standard Docker should create the directory specified by -w, but some alternative container runtimes (like containerd with certain configurations) may not.

7Inspect and rebuild the image

If you're still having issues, do a clean rebuild:

bash
# Remove cached layers and rebuild
docker build --no-cache -t your-image:latest .

# Inspect the resulting image
docker inspect your-image:latest | jq '.[0].Config.WorkingDir'

# Run with verbose output
docker run --rm your-image:latest pwd

# If that works, check what your actual entrypoint does
docker run --rm --entrypoint /bin/sh your-image:latest -c "pwd && ls -la"

Also verify your .dockerignore isn't excluding necessary files:

bash
# Check what gets sent to the build context
cat .dockerignore

Advanced notes

### Multi-Stage Build WORKDIR Behavior

Each FROM instruction in a Dockerfile starts a completely new build stage with its own filesystem. WORKDIR, ENV, and other settings from previous stages do not carry over:

dockerfile
FROM alpine AS stage1
WORKDIR /build
ENV MY_VAR=hello
RUN mkdir -p /output

FROM alpine AS stage2
# /build doesn't exist here
# MY_VAR is not set here
# /output doesn't exist here
WORKDIR /app  # Creates fresh /app directory

To transfer files between stages, use COPY --from=stage1.

### WORKDIR vs RUN mkdir

WORKDIR has special behavior that differs from manually creating directories:

1. WORKDIR creates all parent directories - WORKDIR /a/b/c/d creates the entire path
2. WORKDIR sets ownership to root - unless you've set USER before it
3. WORKDIR persists across RUN commands - unlike cd which only affects one RUN

dockerfile
# These are NOT equivalent:
WORKDIR /app/subdir  # Creates /app and /app/subdir owned by root

# vs
RUN mkdir -p /app/subdir && cd /app/subdir
# Next RUN starts back at the previous WORKDIR, not /app/subdir

### USER and WORKDIR Interaction

When using non-root users, the order of USER and WORKDIR matters:

dockerfile
# WORKDIR before USER - directory owned by root
WORKDIR /app
USER node
RUN touch test.txt  # May fail - can't write to root-owned /app

# Better approach
RUN mkdir -p /app && chown node:node /app
USER node
WORKDIR /app
RUN touch test.txt  # Works - /app is owned by node

### BuildKit and WORKDIR

With Docker BuildKit (default in Docker 23+), WORKDIR behavior is consistent, but older Docker versions or alternative builders like Buildah may have subtle differences. If you encounter issues:

bash
# Force BuildKit
DOCKER_BUILDKIT=1 docker build -t myimage .

# Or use buildx explicitly
docker buildx build -t myimage .

### Container Runtime Differences

While standard Docker (moby/runc) creates WORKDIR directories automatically, alternative runtimes may behave differently:

- containerd (nerdctl): Generally follows Docker behavior
- Podman: Compatible behavior, creates directories
- Garden/Diego (Cloud Foundry): May not create non-existent WORKDIR (historical issue)
- Kubernetes with containerd: Depends on configuration

If deploying to environments with alternative runtimes, always ensure WORKDIR directories exist explicitly.

Frequently asked questions

What does "WORKDIR: cannot change directory to /app: no such file or directory" mean?
The "WORKDIR: cannot change directory to /app: no such file or directory" error indicates that Docker is trying to set the working directory to a path that doesn't exist inside the container. This error can occur in two main scenarios: 1. During container runtime: When you run a container (with docker run) and the image specifies a WORKDIR that doesn't exist in the final image layers.
How do I fix "WORKDIR: cannot change directory to /app: no such file or directory"?
The WORKDIR error occurs when Docker cannot change to the specified directory during a container run or build. This typically happens with multi-stage builds, incorrect base images, or when running containers with a WORKDIR that was not created. Verify your Dockerfile structure or use absolute paths.
What causes "WORKDIR: cannot change directory to /app: no such file or directory"?
Multi-stage build final stage doesn't include the WORKDIR directory Base image was changed and no longer contains expected directory structure Running container with -w flag pointing to non-existent directory (some runtimes)
Is the "WORKDIR: cannot change directory to /app: no such file or directory" error serious?
It is a low-severity error โ€” more of a blocker than a risk. The steps above resolve it.

Official resources & further reading