Signal 11 Fatal Docker & Kubernetes

SIGSEGV (Signal 11) in Docker & Kubernetes

Verdict · SIGSEGV = signal 11; terminated process exits 139 (128 + 11)

SIGSEGV is signal 11, raised when the CPU reports a memory fault the kernel cannot resolve. The default action is terminate with a core dump, and the parent observes 139 = 128 + 11. It is a memory-safety signal, not a memory-limit signal; OOM kills use SIGKILL and 137.

Observed exit139
Signal / meaningSIGSEGV
Default actionTerminate with core dump

Proof commands: confirm the exit status and the killer

Run these before changing anything. The first two identify what the runtime recorded; the third finds a kernel-level kill on the host. Replace the placeholder container ID, pod name or host path with your own.

Docker inspect

docker inspect <container_id> --format '{{.State.Status}} | ExitCode: {{.State.ExitCode}} | OOMKilled: {{.State.OOMKilled}}'

Kubernetes state

kubectl get pod <pod_name> -o jsonpath='{range .status.containerStatuses[*]}{.name}{"\t"}{.lastState.terminated.reason}{"\tExit:"}{.lastState.terminated.exitCode}{"\n"}{end}'

Kernel fault and core

sudo dmesg -T | grep -E -i 'segfault|general protection|traps'; coredumpctl list | tail -n 10

The kernel's segfault line names the process and gives the fault address and trap code. A core file gives the backtrace. If both are absent, enable core capture or attach a debugger; retrying the same image without symbols will only reproduce the same 139.

Three production root causes

Default action: terminate with a core dump. It is a memory fault in native code, a cgo boundary, a JIT or a libc/architecture mismatch. Get a core dump or the runtime crash log and reproduce with symbols; increasing memory will not fix it.

1. A memory-safety defect in native code

C and C++ extensions, Rust unsafe blocks, cgo and JIT-generated code can read or write an invalid address. The crash may occur under load or only with one input. Run the workload under ASan or analyze the core with gdb and the matching debug symbols.

2. A libc or C++ ABI mismatch

A binary built against glibc loaded into a musl image, or a native module built against a different libstdc++, can fault on startup. The same artifact may work on the build host and fail in production. Build native dependencies inside the runtime image and pin the toolchain.

3. Stack exhaustion or a VM/JIT crash

Deep recursion or a thread with a small stack can fault instead of raising a clean exception. The JVM writes hs_err_pid*.log on a native crash; Go prints a goroutine traceback on a fatal signal by default, and GOTRACEBACK=crash additionally aborts with a core dump. Capture the report before changing limits, because a larger stack can mask a logic bug.

Copy-ready fixes for Docker Compose and Kubernetes

The two manifests set explicit memory limits and a termination grace period. Use them as a baseline, then adjust the values to the measured working set of the service.

Compose

docker-compose.yml

Core dumps are controlled by ulimits and kernel.core_pattern on the host, not by the memory limit. If you enable them for debugging, mount a volume for the output and remove it after the investigation.

services:
  app:
    image: ghcr.io/acme/app:1.4.2
    restart: on-failure:3
    stop_grace_period: 20s
    deploy:
      resources:
        limits:
          memory: 1G
        reservations:
          memory: 512M
Kubernetes

deployment.yaml

A container crash does not produce a core file you can read with kubectl by default. The node's core_pattern decides where it goes. Capture dmesg on the node and the application's crash log, then reproduce with the exact image digest and CPU architecture.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: app
spec:
  replicas: 2
  selector:
    matchLabels:
      app: app
  template:
    metadata:
      labels:
        app: app
    spec:
      terminationGracePeriodSeconds: 30
      containers:
        - name: app
          image: ghcr.io/acme/app:1.4.2
          resources:
            requests:
              cpu: "500m"
              memory: "512Mi"
            limits:
              cpu: "2000m"
              memory: "1Gi"
          env:
            - name: GOTRACEBACK
              value: "crash"
Debugging

Capture the fault with symbols

A backtrace is the shortest path from 139 to the offending code.

ulimit -c unlimited
sysctl -w kernel.core_pattern=/var/crash/core.%e.%p
GOTRACEBACK=crash ./app
gdb /usr/local/bin/app /var/crash/core.app.1234

Frequently asked questions

Does exit code 139 mean out of memory?

No. Out-of-memory kills are SIGKILL and exit 137, usually with OOMKilled true. Exit 139 is SIGSEGV, a fault caused by an invalid memory access. A memory limit can cause an allocation to fail, but a clean allocation failure normally surfaces as an application error, not a segfault.

How do I debug a SIGSEGV in a container?

Capture the core with a writable core_pattern and a volume, or use the node's coredumpctl. Then open it with gdb and the same binary plus debug symbols. Enable GOTRACEBACK=crash for Go programs. ASan or a debug build helps when the core cannot be captured.

Why do only some requests cause exit 139?

Memory-safety faults often depend on timing, input size or a race. A null pointer on a rarely used code path, a use-after-free under concurrency or a stack overflow on a deep input can all be intermittent. Reproduce with the same architecture and native dependencies rather than only the same application version.

Follow the status you actually observed, then check the related port or calculator when the failure involves networking, exposure or firewall rules.

Reference basis: POSIX signal semantics (128 + n), Docker container exit status conventions, and Kubernetes container termination behaviour. Verify the exact behaviour against your runtime version before relying on it in an incident.

Last reviewed 2026-11-06 · All exit codes · Developer tools · Privacy