Bash sandbox intermittently fails with apply-seccomp: unshare(CLONE_NEWUSER): Invalid argument
What happens
Roughly one Bash call in three fails with
apply-seccomp: unshare(CLONE_NEWUSER): Invalid argument
printed instead of the command's output. The command does not run. Re-running
the identical command usually succeeds within one to three attempts. The rate
rises as a session ages.
Because the message replaces stdout rather than accompanying it, every failure
initially reads as the command itself failing — a git push that printed
nothing, a stat that found nothing.
Root cause
unshare(CLONE_NEWUSER) implies CLONE_THREAD, which the kernel refuses withEINVAL when the calling process has more than one thread. The sandbox helper
sometimes invokes it from a multithreaded context, which is why the failure is
intermittent rather than constant.
Reduced to a standalone reproducer — forks a child per case so the parent's
thread state is untouched, then calls libc.unshare(CLONE_NEWUSER):
single-threaded: OK
multithreaded : FAIL EINVAL (Invalid argument)
Measured in one session: 5 failures in 19 Bash calls.
This is not #43454
https://github.com/anthropics/claude-code/issues/43454 iswrite /proc/self/setgroups … Permission denied — EPERM, a nested-userns
capability problem. This is EINVAL from a multithreaded caller. Same helper,
different failure, different fix.
Ruled out
- AppArmor.
kernel.apparmor_restrict_unprivileged_userns=1is set, but
/etc/apparmor.d/unprivileged_userns grants allow userns, unshare --user
succeeds from a shell, and journalctl -k --since '-14d' shows zero
userns_create denials.
- Missing packages. Sandboxing works; it just fails intermittently.
- Nesting. Not running in a container.
Environment
- Claude Code 2.1.233
Linux 7.0.0-28-generic #28~24.04.1-Ubuntu SMP PREEMPT_DYNAMIC x86_64- Ubuntu 24.04, bare metal, no container
sandbox.enabled: true,autoAllowBashIfSandboxed: true
Suggested fix
Perform the unshare before spawning helper threads, or do it in a
single-threaded forked child. Failing that, retry internally on EINVAL rather
than surfacing it, and never print the helper's error in place of the command's
own output — that conflation is most of the operational cost.
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗