How to fix container_linux.go:380: starting container process caused: exec: "/bin/sh": stat /bin/sh: no such file or directory in Docker

DockerINTERMEDIATEMEDIUMUpdated Dec 6, 2025ยท 205 views

This error occurs when running containers built FROM scratch because scratch images contain absolutely nothing - no shell, no libraries, no system files. You must use exec form for CMD/ENTRYPOINT and ensure your binary is statically compiled.

Quick fix

Fixes container_linux.go:380: starting container process caused: exec: "/bin/sh": stat /bin/sh: no such file or directory

# WRONG - Shell form tries to use /bin/sh
FROM scratch
COPY myapp /myapp
CMD /myapp

# CORRECT - Exec form runs binary directly
FROM scratch
COPY myapp /myapp
CMD ["/myapp"]

# Also correct with arguments
CMD ["/myapp", "--port", "8080"]
  1. Use exec form for CMD and ENTRYPOINT
  2. Ensure your binary is statically compiled
  3. Disable CGO for Go applications
  4. Use a minimal base image instead of scratch if you need a shell
docker โ€” error
# WRONG - Shell form tries to use /bin/sh
FROM scratch
COPY myapp /myapp
CMD /myapp
# CORRECT - Exec form runs binary directly
FROM scratch
COPY myapp /myapp
CMD ["/myapp"]
# Also correct with arguments
CMD ["/myapp", "--port", "8080"]
container_linux.go:380: starting container process caused: exec: "/bin/sh": stat /bin/sh: no such file or directory

What this error means

This error indicates that Docker is trying to execute a command using `/bin/sh` (the shell), but the container has no shell installed. This is most common with images built `FROM scratch`, which is a completely empty base image containing no files whatsoever. When you use the "shell form" of CMD or ENTRYPOINT in your Dockerfile (e.g., `CMD myapp --start`), Docker actually runs it as `/bin/sh -c "myapp --start"`. Since scratch images have no shell, this fails immediately. The scratch base image is designed for creating minimal containers that contain only your application binary. It provides the smallest possible image size and attack surface, but requires that: 1. Your binary is statically compiled (no external library dependencies) 2. All commands use "exec form" (JSON array syntax) instead of "shell form" 3. You don't attempt to use RUN commands in the Dockerfile after the FROM scratch line

Typical symptoms

  • Container fails to start with 'exec: "/bin/sh": stat /bin/sh: no such file or directory'
  • Container exits immediately after docker run with exit code 1
  • Error mentions 'container_linux.go' or 'standard_init_linux.go'
  • Docker Compose service repeatedly restarts
  • CI/CD pipeline fails when deploying scratch-based images
  • docker exec fails because there's no shell to execute commands
  • Multi-stage build final image won't start despite working build stage

Common causes

  1. Using shell form CMD (CMD /app) instead of exec form (CMD ["/app"]) with a scratch image
  2. Using shell form ENTRYPOINT instead of exec form with a scratch image
  3. Attempting RUN commands after FROM scratch (scratch has no shell to execute them)
  4. Binary requires dynamic libraries not present in the scratch image
  5. Binary was compiled with CGO enabled, creating libc dependencies
  6. Copying a shell script as entrypoint without copying a shell to execute it
  7. Multi-stage build copying a dynamically linked binary to scratch

How to fix "container_linux.go:380: starting container process caused: exec: "/bin/sh": stat /bin/sh: no such file or directory"

1Use exec form for CMD and ENTRYPOINT

The most common fix is to use JSON array syntax (exec form) instead of string syntax (shell form):

dockerfile
# WRONG - Shell form tries to use /bin/sh
FROM scratch
COPY myapp /myapp
CMD /myapp

# CORRECT - Exec form runs binary directly
FROM scratch
COPY myapp /myapp
CMD ["/myapp"]

# Also correct with arguments
CMD ["/myapp", "--port", "8080"]

The exec form CMD ["/myapp"] executes the binary directly via the kernel's execve() syscall without needing a shell. The shell form CMD /myapp is interpreted as /bin/sh -c "/myapp", which fails without a shell.

2Ensure your binary is statically compiled

Your binary must have no runtime dependencies on shared libraries. For Go applications:

bash
# Check if your binary is statically linked
ldd myapp
# Should output: "not a dynamic executable" or "statically linked"

# If it shows dependencies, rebuild statically
CGO_ENABLED=0 go build -ldflags="-s -w" -o myapp .

For other languages:

bash
# C/C++ - use static linking
gcc -static -o myapp myapp.c

# Rust - static linking is default for musl targets
rustup target add x86_64-unknown-linux-musl
cargo build --release --target x86_64-unknown-linux-musl

If ldd shows any dependencies like libc.so.6, the binary won't work in a scratch image.

3Disable CGO for Go applications

CGO enables Go to call C code, but this creates dynamic library dependencies. Disable it for scratch images:

dockerfile
FROM golang:1.21 AS builder
WORKDIR /app
COPY . .

# CGO_ENABLED=0 is crucial for scratch images
RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-s -w" -o /myapp .

FROM scratch
COPY --from=builder /myapp /myapp
CMD ["/myapp"]

Common build flags for Go:
- CGO_ENABLED=0 - Disable CGO for pure Go compilation
- -ldflags="-s -w" - Strip debug info for smaller binary
- GOOS=linux - Cross-compile for Linux if building on Mac/Windows

4Use a minimal base image instead of scratch if you need a shell

If you need shell functionality, use a minimal image like Alpine, BusyBox, or distroless:

dockerfile
# Option 1: Alpine (~5MB) - has shell and package manager
FROM alpine:3.19
COPY myapp /myapp
CMD ["/myapp"]

# Option 2: BusyBox (~1MB) - has shell, minimal tools
FROM busybox:1.36
COPY myapp /myapp
CMD ["/myapp"]

# Option 3: Distroless (~2MB) - no shell but has C libraries
FROM gcr.io/distroless/static-debian12
COPY myapp /myapp
CMD ["/myapp"]

Image size comparison:
- scratch: 0 bytes (truly empty)
- distroless/static: ~2MB
- busybox: ~1MB
- alpine: ~5MB

5Copy required certificates for HTTPS

Scratch images don't have CA certificates, so HTTPS requests will fail. Copy them from your build stage:

dockerfile
FROM golang:1.21 AS builder
# ... build steps ...

FROM scratch

# Copy CA certificates for HTTPS
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/

# Copy timezone data if needed
COPY --from=builder /usr/share/zoneinfo /usr/share/zoneinfo

COPY --from=builder /myapp /myapp
CMD ["/myapp"]

Alternatively, copy from Alpine:

dockerfile
FROM alpine:3.19 AS certs
RUN apk add --no-cache ca-certificates

FROM scratch
COPY --from=certs /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
6Debug using a multi-stage Dockerfile

If you're unsure why your scratch image fails, add a debug stage that uses Alpine to test the binary:

dockerfile
FROM golang:1.21 AS builder
WORKDIR /app
COPY . .
RUN CGO_ENABLED=0 go build -o /myapp .

# Debug stage - use this to troubleshoot
FROM alpine:3.19 AS debug
COPY --from=builder /myapp /myapp
RUN ldd /myapp || echo "Statically linked"
CMD ["/myapp"]

# Production stage
FROM scratch AS production
COPY --from=builder /myapp /myapp
CMD ["/myapp"]

Build and test each stage:

bash
# Test debug stage
docker build --target debug -t myapp:debug .
docker run myapp:debug

# Build production stage
docker build --target production -t myapp:prod .
7Add a shell for debugging scratch containers

If you need to debug a running scratch container, you can copy busybox into it:

bash
# Get busybox binary
docker create --name busybox busybox
docker cp busybox:/bin/busybox ./busybox
docker rm busybox

# Copy into running container
docker cp ./busybox mycontainer:/busybox

# Now you can exec with busybox
docker exec -it mycontainer /busybox sh

Or include busybox in your image during development:

dockerfile
FROM busybox AS busybox

FROM scratch
COPY --from=busybox /bin/busybox /busybox
COPY myapp /myapp
CMD ["/myapp"]

# Debug with: docker exec -it container /busybox sh

Remove the busybox lines for production builds.

Advanced notes

### Why Scratch Images Exist

The scratch image is designed for:
- Minimal attack surface: No shell means no shell exploits
- Smallest possible size: Only your binary, nothing else
- Compliance: Some security policies require minimal base images
- Fast startup: Less filesystem overhead

### Common Multi-Architecture Issues

When building for multiple architectures, ensure your binary matches the target:

dockerfile
FROM --platform=$BUILDPLATFORM golang:1.21 AS builder
ARG TARGETOS TARGETARCH
WORKDIR /app
COPY . .
RUN CGO_ENABLED=0 GOOS=$TARGETOS GOARCH=$TARGETARCH go build -o /myapp .

FROM scratch
COPY --from=builder /myapp /myapp
CMD ["/myapp"]

Build for multiple platforms:

bash
docker buildx build --platform linux/amd64,linux/arm64 -t myapp:latest .

### The "no such file" Error with Correct Exec Form

If you're using exec form but still getting this error, your binary likely has dynamic library dependencies. Check with:

bash
# In your builder stage
docker run --rm builder-image ldd /myapp

Common culprits:
- net package in Go: Use CGO_ENABLED=0 or -tags netgo
- sqlite3 in Go: Requires CGO - use a different database or pure Go driver
- glibc vs musl: Build with musl for truly static binaries

### Security Considerations

Scratch images are excellent for security:

bash
# Scanning a scratch image for vulnerabilities
docker scout cves myapp:scratch
# Typically shows 0 vulnerabilities since there's no OS

# vs scanning an alpine image
docker scout cves myapp:alpine
# May show OS-level CVEs

However, ensure your application handles signals correctly (no init process in scratch):

go
// Handle graceful shutdown in Go
signal.Notify(sigChan, syscall.SIGTERM, syscall.SIGINT)

Frequently asked questions

What does "container_linux.go:380: starting container process caused: exec: "/bin" mean?
This error indicates that Docker is trying to execute a command using /bin/sh (the shell), but the container has no shell installed. This is most common with images built FROM scratch, which is a completely empty base image containing no files whatsoever. , CMD myapp --start), Docker actually runs it as /bin/sh -c "myapp --start".
How do I fix "container_linux.go:380: starting container process caused: exec: "/bin"?
This error occurs when running containers built FROM scratch because scratch images contain absolutely nothing - no shell, no libraries, no system files. You must use exec form for CMD/ENTRYPOINT and ensure your binary is statically compiled.
What causes "container_linux.go:380: starting container process caused: exec: "/bin"?
Using shell form CMD (CMD /app) instead of exec form (CMD ["/app"]) with a scratch image Using shell form ENTRYPOINT instead of exec form with a scratch image Attempting RUN commands after FROM scratch (scratch has no shell to execute them)
Is the "container_linux.go:380: starting container process caused: exec: "/bin" error serious?
It is a medium-severity error โ€” more of a blocker than a risk. The steps above resolve it.

Official resources & further reading