KhueApps
Home/DevOps/Fixing “OCI runtime create failed” when starting Docker containers

Fixing “OCI runtime create failed” when starting Docker containers

Last updated: October 06, 2025

Overview

The error “OCI runtime create failed: runc create failed: unable to start container process” is a wrapper around a more specific cause. The key is to read the trailing part of the message and then verify image entrypoints, mounts/permissions, cgroups, security profiles (SELinux/AppArmor/seccomp), and storage.

This guide provides quick diagnostics, reproducible examples, and targeted fixes for Docker hosts on Linux (and notes for WSL2/macOS).

Quickstart (fast triage)

  1. Reproduce and capture full error text.
    • Run with debug logs enabled:
      sudo dockerd --debug 2> /tmp/dockerd.debug &   # or enable in daemon.json and restart
      docker run --rm alpine:3.20 echo OK
      
    • Note the final clause after “unable to start container process:” (e.g., exec not found, permission denied, invalid mount).
  2. Check image entrypoint/cmd and availability.
    docker inspect --format='Entrypoint={{.Config.Entrypoint}} Cmd={{.Config.Cmd}}' IMAGE
    
  3. Validate volumes and permissions.
    docker run --rm -v /host/path:/mnt alpine:3.20 sh -lc 'id && ls -l /mnt'
    
  4. Verify cgroups/security/storage on the host.
    docker info | sed -n '1,120p'
    df -h /var/lib/docker
    
  5. If in doubt, temporarily relax security to confirm cause (then revert):
    docker run --rm --security-opt seccomp=unconfined --security-opt apparmor=unconfined alpine:3.20 true
    

Minimal working example (MWE)

Use this to confirm your host is healthy and to test entrypoints.

  • Dockerfile:
FROM alpine:3.20
RUN adduser -D app
COPY run.sh /usr/local/bin/run.sh
RUN chmod +x /usr/local/bin/run.sh
USER app
ENTRYPOINT ["/usr/local/bin/run.sh"]
  • run.sh:
#!/bin/sh
# Tiny sanity check
echo "Container OK as $(id -u):$(id -g)"
  • Build and run:
docker build -t mwe:ok .
docker run --rm mwe:ok

If this succeeds, your runtime is generally fine. If your app image fails, compare its entrypoint, user, and mounts against this MWE.

Common causes and concrete fixes

1) Executable not found / wrong interpreter

Symptoms:

  • Error ends with: exec: "app": executable file not found in $PATH
  • Or: no such file or directory (missing interpreter) or exec format error (wrong architecture)

Fix:

  • Ensure the binary/script exists and is executable.
    docker run --rm -it IMAGE sh -lc 'which app || ls -l /path/to/app'
    
  • For scripts, check shebang and line endings (no CRLF):
    docker run --rm -v "$PWD":/w -w /w alpine:3.20 sh -lc 'apk add --no-cache file && file -b run.sh'
    # If CRLF: convert locally
    dos2unix run.sh
    
  • Provide missing interpreter in image or change shebang (e.g., #!/usr/bin/env bash).
  • Pull for correct architecture or set platform:
    docker run --rm --platform=linux/amd64 IMAGE true
    

2) Permission denied on bind mounts

Symptoms:

  • Error ends with: permission denied, operation not permitted
  • A directory is mounted but container user cannot read/execute

Fix:

  • Adjust ownership/permissions on host or run as a matching user:
    sudo chown -R 1000:1000 /host/path
    chmod -R u+rx /host/path
    docker run --rm -u 1000:1000 -v /host/path:/data IMAGE
    
  • On SELinux hosts, label volumes:
    docker run --rm -v /host/path:/data:Z IMAGE
    # or :z for shared among containers
    
  • Avoid mounting from noexec partitions. Check and remount without noexec:
    mount | grep -E '/var/lib/docker|/tmp'
    

3) Invalid or mismatched volume sources

Symptoms:

  • Error mentions: not a directory, file exists, or invalid argument

Fix:

  • Ensure host paths exist and type matches the container expectation:
    mkdir -p /host/dir
    docker run -v /host/dir:/app/dir IMAGE
    
  • Avoid trailing slashes that create dir vs file mismatches.
  • Resolve symlinks to accessible real paths.

4) Security profiles (seccomp/AppArmor/SELinux)

Symptoms:

  • Syscall denials; error may not show details.

Fix:

  • Temporarily disable to confirm:
    docker run --rm --security-opt seccomp=unconfined --security-opt apparmor=unconfined IMAGE
    
  • For SELinux AVC denials, check:
    sudo journalctl -t setroubleshoot -t audit | tail -n 50
    
    Then relabel volumes (:Z/:z) or adjust policy.

5) Cgroups driver or kernel support issues

Symptoms:

  • Errors around cgroups, pids, devices, or freezer

Fix:

  • Align Docker with systemd cgroups (recommended on modern distros):
    sudo mkdir -p /etc/docker
    sudo tee /etc/docker/daemon.json >/dev/null <<'JSON'
    {
      "exec-opts": ["native.cgroupdriver=systemd"]
    }
    JSON
    sudo systemctl restart docker
    
  • On cgroup v2-only hosts, ensure recent Docker/Containerd/Runc versions.
  • In WSL2: wsl.exe --shutdown then restart Docker Desktop.

6) Storage driver and disk pressure

Symptoms:

  • Error may include overlayfs/aufs failures; low disk space

Fix:

  • Ensure space and inodes:
    df -h /var/lib/docker
    df -i /var/lib/docker
    
  • Prune safely:
    docker system df
    docker system prune -af --volumes
    
  • Keep Storage Driver as overlay2 on Linux unless you have a reason otherwise.

7) Rootless Docker specifics

Symptoms:

  • newuidmap/newgidmap errors, overlayfs permission denied

Fix:

  • Install shadow-utils (subuid/subgid) and configure ranges:
    grep "$(whoami)" /etc/subuid /etc/subgid || echo "$(whoami):100000:65536" | sudo tee -a /etc/subuid /etc/subgid
    
  • Use fuse-overlayfs if kernel lacks overlayfs for unprivileged users.

Diagnostics toolbox

  • Get container create-time detail:
    docker events --since 1m &
    docker run --name test IMAGE ... || true
    docker inspect test | sed -n '1,200p'
    docker logs test 2>&1 | tail -n +1
    
  • Host logs:
    sudo journalctl -u docker -n 200 --no-pager
    sudo journalctl -u containerd -n 200 --no-pager
    dmesg | tail -n 100
    

Symptom-to-fix quick map

Symptom tailLikely causeFast fix
executable file not foundWrong entrypoint/pathInspect, correct path, ensure executable bit
no such file or directoryMissing interpreter/CRLFInstall shell, fix shebang, dos2unix
permission deniedMount perms/SELinuxchown/chmod, :Z, avoid noexec
invalid argument (mount)Wrong host path/typeCreate path, correct :ro/:rw, dir vs file
operation not permittedSeccomp/AppArmorTemporarily unconfine; update profile

Pitfalls

  • CRLF line endings in shell scripts cause “no such file or directory”.
  • Mismatched CPU architecture triggers “exec format error”.
  • Mounting from directories owned by root without proper permissions for a non-root container user.
  • Relying on relative host paths with -v; use absolute paths.
  • Running from a noexec filesystem (common in hardened hosts) blocks script execution.

Performance notes

  • Keep images small and entrypoints simple to reduce cold-start overhead.
  • Prefer overlay2 on ext4/xfs with ftype=1; slow storage increases container start latency.
  • Avoid excessive bind mounts; deep directory trees can slow mount setup.
  • Using seccomp=unconfined or privileged may mask issues but has security costs; use only for debugging.

Tiny FAQ

  • How do I see the real root cause? Read the last clause of the error and check daemon logs with journalctl; runc’s message is appended there.
  • Why does a file “exist” but still says not found? Often missing interpreter or CRLF endings; the kernel can’t load the script/binary.
  • Can I fix this by using --privileged? It may mask security denials but is not a fix; identify and address the specific policy or permission.
  • Does restarting Docker help? It can clear transient state: sudo systemctl restart docker (and containerd). Useful after daemon.json changes.
  • What about Docker Desktop/WSL2? Restart the VM/WSL2 (wsl.exe --shutdown), ensure enough disk, and check the Linux kernel version inside the VM.

Series: Docker

DevOps