In this article
Failure to create a thread in a container can mean pids.max has been reached even while RAM and the GPU remain available. The pids controller counts kernel tasks, including threads. A process-only view of ps can therefore understate consumption of the configured allowance.
Failure to create a thread in a container can mean pids.max has been reached even while RAM and the GPU remain available. The pids controller counts kernel tasks, including threads. A process-only view of ps can therefore understate consumption of the configured allowance.
Attach the failure to the effective group
Save the exact error, timestamp and application PID. Locate its cgroup through the host view of /proc/PID/cgroup and read pids.current, pids.max and pids.events. The max event counter records failures caused by the limit rather than terminated processes. Measure its increase during reproduction. A child container may have a generous limit while a tighter ancestor constrains task creation across every descendant beneath it.
Count threads separately
A single Python process can create threads for libraries, networking clients and input preparation. A PID list without TIDs does not describe that workload. Compare application tasks with pids.current, including diagnostic commands, background workers and accidentally duplicated service instances. Once the limit is reached, docker exec may itself fail to create a shell. That complicates investigation but does not establish that the main application process has stopped running.
Investigate growth after an update
Suppose an illustrative container has pids.max set to 128. Adding preparation workers brings pids.current close to 128, and another thread start returns EAGAIN. Reducing the worker count restores task creation. This supports the pids-limit hypothesis when pids.events also increases. If the event counter remains stable, investigate other task-creation constraints and actual memory consumption instead of automatically raising this particular limit.
| Incident record field | What the check establishes |
|---|---|
| PID and cgroup path | The failure belongs to the intended instance |
| pids.current before and after | The change in task count is visible |
| Increase in the max event | The controller rejected task creation |
| Ancestor limits | The shared boundary has also been checked |
Choose a bounded correction
First remove duplicate processes and unnecessary parallelism. If the thread count is justified, recalculate the pids budget with room for startup and maintenance, then update the declared configuration. An unlimited allowance can conceal uncontrolled task creation. Do not kill arbitrary processes by name: a container may contain an important parent and legitimate children. A separate test environment with the same launch structure is sufficient for controlled reproduction.
Verify another full startup
Exercise cold startup, steady workload and graceful shutdown. At each stage, save task counts and event deltas. Check that an agreed diagnostic command can still execute at peak load. The resulting artifact should state the allowed worker count, maximum observed task consumption and pids.max setting. It describes a measured process budget, while leaving room to reassess future library changes that might create additional threads. Compare this record with the next release rather than assuming an unchanged image name implies an unchanged process tree.
Preserve the child tree after work completes. Background tasks can explain consumption during the next attempt even when the current operation has ended and the main application appears idle.
Related operational reading: gpu containers vs vms; server preparation.