Docker Error Guide: 'pthread_create failed: Operation not permitted' — Fix seccomp Syscall Blocks
Fix Docker 'pthread_create failed: Operation not permitted' and runc EPERM caused by an old seccomp profile blocking clone3. Update Docker/runc or loosen the seccomp profile.
- #docker
- #troubleshooting
- #errors
- #seccomp
Stuck on this Docker with AI error? Get the free incident triage checklist
A one-page PDF — the exact steps to isolate, fix, and verify a production error like this one. No spam, unsubscribe anytime.
Overview
A container built on a newer base image fails to start, or its process crashes at launch, because a syscall it needs is denied by Docker’s default seccomp profile. The two faces of this problem look like a runtime/exec permission failure:
docker: Error response from daemon: failed to create task for container: failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: exec: "runc": permission denied: unknown.
runtime/cgo: pthread_create failed: Operation not permitted
SIGABRT: abort
The pthread_create failed: Operation not permitted line is the tell: the container’s glibc tried a newer syscall — most often clone3 — and an outdated seccomp allowlist returned EPERM instead of permitting it. Newer glibc (Ubuntu 22.04+, Fedora, recent Alpine builds) uses clone3, which older Docker/runc seccomp profiles did not include.
Symptoms
- Containers based on recent images (glibc 2.34+) crash immediately with
pthread_create failed: Operation not permitted. - Go/CGO programs abort with
SIGABRTright after start. - The same image runs fine on a newer Docker host but fails on an old one.
runccreate fails withpermission denied/operation not permittedon an aging engine.- Running with
--security-opt seccomp=unconfinedmakes the container start (a diagnostic clue, not a fix).
Common Root Causes
- Old Docker/runc default seccomp profile — its allowlist predates
clone3, so newer glibc’s threading path is blocked. - New-glibc image on an old engine — modern base images call syscalls the host’s seccomp profile does not know about.
- Outdated
libseccompon the host — the daemon’s seccomp library is too old to translate newer syscall numbers, so they fall through to the default deny action. - A custom seccomp profile with a restrictive default action — a hand-written profile that denies (rather than allows/logs) unknown syscalls, missing
clone3/faccessat2/rseq. - Kernel/userspace skew — a recent kernel exposing new syscalls paired with an old container stack that filters them.
Diagnostic Workflow
First, confirm versions — the fix hinges on how old Docker, runc, and libseccomp are:
docker version --format 'Engine {{.Server.Version}}'
runc --version
dpkg -l libseccomp2 2>/dev/null || rpm -q libseccomp
Prove seccomp is the cause by running the exact image with seccomp disabled. If it now works, seccomp was the culprit:
docker run --rm --security-opt seccomp=unconfined <image> true
Identify the specific blocked syscall using strace inside a privileged debug run (look for EPERM on clone3):
docker run --rm --privileged <image> sh -c 'command -v strace' 2>/dev/null
strace -f -e trace=clone,clone3 <program> # on the host binary, if reproducible
Read the daemon log around the failure:
journalctl -u docker --since '15 min ago' | grep -i 'seccomp\|operation not permitted\|clone3'
Check what seccomp mode the daemon applies by default:
docker info --format '{{.SecurityOptions}}'
Example Root Cause Analysis
A team upgraded their application base image from Ubuntu 20.04 to 22.04. On developer laptops (recent Docker) everything worked, but a long-lived production host running an old engine crashed every container:
docker run --rm registry.internal/api:2.0 /api
# runtime/cgo: pthread_create failed: Operation not permitted
# SIGABRT: abort
Running the same image with --security-opt seccomp=unconfined started cleanly, which pointed straight at seccomp. docker version showed an engine whose default seccomp profile predated clone3 support, and glibc 2.35 in Ubuntu 22.04 uses clone3 for thread creation — so the syscall was silently denied and glibc aborted.
The correct fix was to update the container stack, which ships a current seccomp profile that allows clone3:
sudo apt-get update
sudo apt-get install --only-upgrade docker-ce docker-ce-cli containerd.io libseccomp2
sudo systemctl restart docker
docker run --rm registry.internal/api:2.0 /api # starts cleanly
Where the engine could not be upgraded immediately, a stop-gap was a custom seccomp profile based on the default with clone3 added — much safer than unconfined:
# Start from Docker's default profile, add the missing syscall names, then:
docker run --rm --security-opt seccomp=/etc/docker/seccomp-clone3.json <image> /api
Using --security-opt seccomp=unconfined also works but disables syscall filtering entirely, weakening container isolation — acceptable only as a temporary diagnostic, not a production setting.
Prevention Best Practices
- Keep Docker Engine,
runc/containerd, andlibseccompcurrent so the default seccomp profile knows about new syscalls likeclone3. - Test images built on new base OSes against your oldest production Docker host before rolling out.
- Prefer updating the engine over disabling seccomp; never ship
seccomp=unconfinedto production — it removes a key isolation layer. - If you must customize, base your profile on Docker’s default and add only the specific syscalls you need, keeping a permissive default action for forward compatibility.
- Pin and track
libseccompin your host provisioning so it is not left behind during partial upgrades. - Standardize the Docker/containerd version across the fleet to avoid works-here/fails-there skew.
Quick Command Reference
# Versions that determine the fix
docker version --format '{{.Server.Version}}' && runc --version
# Confirm seccomp is the cause (diagnostic only)
docker run --rm --security-opt seccomp=unconfined <image> true
# Update the whole container stack (the real fix)
sudo apt-get install --only-upgrade docker-ce docker-ce-cli containerd.io libseccomp2
sudo systemctl restart docker
# Run with a custom profile that adds clone3 (stop-gap)
docker run --rm --security-opt seccomp=/etc/docker/seccomp-clone3.json <image>
# Inspect the blocked syscall
journalctl -u docker --since '15 min ago' | grep -i 'clone3\|operation not permitted'
Conclusion
pthread_create failed: Operation not permitted is almost always a seccomp problem: a newer image’s glibc calls clone3, and an old Docker/runc/libseccomp stack denies it. Confirm by running with seccomp=unconfined — if that works, seccomp is the cause. The right fix is to update Docker, runc, and libseccomp so the default profile permits the newer syscalls. A custom profile that adds clone3 is a reasonable stop-gap; unconfined should stay a temporary diagnostic because it strips syscall filtering and weakens isolation.
For related runtime failures, see the OCI runtime create failed guide, the failed to create shim task guide, and more fixes in the Docker guides.
Fixed it? Get 500 Docker with AI & DevOps AI prompts — free
500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.
- 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
- Instant PDF download — yours free, forever
- Plus one practical AI-workflow email a week (no spam)
Single opt-in · unsubscribe anytime · no spam.
Stuck on this? Start guided troubleshooting
Open an interactive diagnostic session with this error already loaded. Work a step-by-step plan, record what each check returns, land on a root cause, and export a clean incident summary — no account needed to start.
Did this fix your issue?
Solved it a different way?
Share the fix that worked for you — reviewed, then published to help the next engineer.
That looks like it may contain a secret (key, token, password, or connection string). Please remove it — a note with a detected secret can’t be published.
Thanks — that helps. Published notes appear after a quick review.
Trending errors this week
The error guides other engineers are actually reading right now.
- 1mount: wrong fs type, bad option, bad superblock
- 2Docker 'failed to set up container networking': Fix the Bridge and IP Pool
- 3Docker 'failed to create shim task': How to Fix the containerd Runtime Error
- 4Transport endpoint is not connected
- 5modprobe: FATAL: Module not found
- 6mount: wrong fs type, bad option, bad superblock
Get 500 Battle-Tested DevOps AI Prompts — Free
500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.
- 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
- Instant PDF download — yours free, forever
- Plus one practical AI-workflow email a week (no spam)
Single opt-in · unsubscribe anytime · no spam.