Containers Advanced

Docker Container Exit Code 139: Troubleshooting Segmentation Fault on Alpine Linux

Resolve Docker container exit code 139 (segmentation fault) on Alpine Linux. Common causes include glibc/musl incompatibility, memory limits, and application bugs.

πŸ‘¨β€πŸ’»
Senior Systems Architect • Verified in Staging Labs

Resolve Docker container exit code 139 (segmentation fault) on Alpine Linux. Common causes include glibc/musl incompatibility, memory limits, and application bugs.

When a Docker container abruptly stops with an exit code of 139, it's often an indication of a critical runtime error: a segmentation fault. This issue is particularly prevalent and often more complex to diagnose in containers built on Alpine Linux due to its unique musl C standard library implementation, which differs significantly from the glibc commonly used by most other Linux distributions. As a Systems Administrator or DevOps engineer, understanding and resolving this specific error is crucial for maintaining stable containerized applications.

Symptom & Error Signature

The most direct symptom you'll observe is your container failing to start or crashing shortly after launch. Checking the container's status will reveal the exit code:

# Check the status of all containers, including exited ones
docker ps -a

Expected Output:

CONTAINER ID   IMAGE          COMMAND                  CREATED         STATUS                     PORTS     NAMES
a1b2c3d4e5f6   my-app:latest  "/usr/local/bin/entryp…" 2 minutes ago   Exited (139) 2 minutes ago           my-app-container

Further inspection of the container's logs may not always provide a clear stack trace, often just indicating the segmentation fault itself:

# View logs for the failing container
docker logs my-app-container

Typical Log Output:

[2026-11-02 10:30:05] Application starting...
Segmentation fault

In some cases, the host's kernel message buffer (dmesg) might contain additional information, especially if the fault involves memory protection:

# Check host kernel messages for recent segfaults
dmesg -T | grep 'segmentation fault'

Potential dmesg Output:

[Mon Nov 2 10:30:05 2026] my-app[12345]: segfault at 7f0a12345678 ip 00007f0a12345678 sp 00007f0a98765432 error 4 in libsomething.so[7f0a12345000+1000]

Root Cause Analysis

A segmentation fault (SIGSEGV, signal 11) indicates that a program tried to access a memory location that it was not allowed to access, or attempted to access it in an illegal way (e.g., writing to a read-only segment). In the context of Docker containers, especially those based on Alpine Linux, the root causes typically fall into these categories:

  1. glibc vs. musl C Standard Library Incompatibility (Primary Suspect): This is by far the most common cause on Alpine Linux. Alpine uses musl libc, a lightweight, modern, and secure C standard library. Many applications, particularly those distributed as pre-compiled binaries, dynamically link against glibc (GNU C Library), which is standard on distributions like Ubuntu, Debian, CentOS, etc. Attempting to run a glibc-dependent binary directly on a musl-based system without proper compatibility layers will frequently result in a segmentation fault because symbol lookups and runtime library calls fail or behave unexpectedly.

  2. Memory Exhaustion or Incorrect Memory Limits: The container might be configured with insufficient memory (--memory or mem_limit in Docker Compose) for the application to operate correctly. While an Out-Of-Memory (OOM) error usually results in exit code 137 (SIGKILL), severe memory pressure or incorrect memory access when nearing limits can sometimes manifest as a segmentation fault before the OOM killer is invoked.

  3. Application Bugs: The application itself contains a bug, such as:

    • Dereferencing a null pointer.
    • Accessing an array out of bounds (buffer overflow/underflow).
    • Using freed memory (use-after-free).
    • Corrupting the stack. These are common in applications written in C/C++ or other languages that use native extensions (e.g., Python, Node.js, Ruby with C extensions).
  4. Missing or Incompatible Dynamic Linker/Libraries: The container image might be missing essential shared libraries (.so files) that the application needs at runtime, or it might have incompatible versions. This can happen if the Dockerfile doesn't explicitly install all runtime dependencies.

  5. JVM/Node.js Native Module Issues: For Java applications, specific JVM versions or configurations, especially those interacting with JNI (Java Native Interface) libraries, can trigger segfaults. Similarly, Node.js applications using native C++ modules can experience this if the modules are compiled against a different libc or Node.js ABI than what's available in the container.

Step-by-Step Resolution

Debugging a segmentation fault on Alpine Linux requires a methodical approach. Start with the most common causes and work your way to more complex application-level debugging.

1. Inspect Container Logs and Host Kernel Messages

Begin by thoroughly reviewing all available logs to gather clues.

# Check container exit status and logs
docker ps -a
docker logs my-app-container

# Check host system kernel logs for segfault entries
# -T (or --time-format=human) for human-readable timestamps
# -l info,err,crit,alert,emerg for relevant log levels
dmesg -T | grep 'segfault|fault'

A dmesg entry showing a segfault can provide the exact memory address and potentially the shared library involved, which is invaluable for root cause analysis.

2. Address glibc/musl Incompatibility (Most Common Fix)

If your application isn't explicitly built for musl, this is your prime suspect. You have several strategies:

Option A: Use glibc Compatibility Layer in Alpine

For existing Alpine-based images, you can often install a glibc compatibility package. A popular choice is the alpine-pkg-glibc package from the sgerrand repository.

While convenient, adding glibc via a third-party repository introduces an external dependency and slightly increases image size. For critical production systems, consider Option B for greater stability and official support.

Dockerfile Example:

# Start with your existing Alpine base image
FROM alpine:3.18

# Add the sgerrand glibc repository and install glibc
# Ensure to replace '3.18' with your Alpine version if different
RUN apk add --no-cache curl 
    && curl -sL https://alpine-pkgs.sgerrand.com/sgerrand.rsa.pub -o /etc/apk/keys/sgerrand.rsa.pub 
    && echo "https://alpine-pkgs.sgerrand.com/glibc-compatibility" >> /etc/apk/repositories 
    && apk add --no-cache glibc glibc-locales glibc-bin 
    && rm -rf /var/cache/apk/* /tmp/*

# Now install your application dependencies and run your application
# Example: If running a Python application that uses glibc-dependent native extensions
RUN apk add --no-cache python3 py3-pip
COPY requirements.txt /app/
WORKDIR /app
RUN pip install -r requirements.txt

COPY . /app
CMD ["python3", "app.py"]
Option B: Switch to a glibc-based Base Image

This is often the most robust and recommended solution if glibc incompatibility is the root cause. Using a glibc-based distribution like debian:slim or ubuntu as your base image guarantees glibc support out-of-the-box.

Dockerfile Example:

# Use a glibc-based base image (e.g., Debian Slim)
FROM debian:slim

# Install your application dependencies as usual for Debian/Ubuntu
RUN apt-get update && apt-get install -y --no-install-recommends 
    python3 
    python3-pip 
    # Add any other system dependencies your app needs
    && rm -rf /var/lib/apt/lists/*

COPY requirements.txt /app/
WORKDIR /app
RUN pip install -r requirements.txt --no-cache-dir

COPY . /app
CMD ["python3", "app.py"]
Option C: Recompile for musl

If you have access to the application's source code, the ideal solution is to recompile it specifically for musl libc. This ensures maximum compatibility and benefits from Alpine's lightweight nature. This typically involves using a musl-compatible toolchain during compilation.

3. Review and Adjust Container Memory Limits

If the issue persists or if you suspect memory pressure, investigate your Docker memory limits.

# If using docker run, check the --memory flag
docker run -d --name my-app-container --memory="512m" my-app:latest

# If using Docker Compose, check the mem_limit key in your service definition
# docker-compose.yml
services:
  my-app:
    image: my-app:latest
    mem_limit: 512m # Example: 512MB

Gradually increase memory limits to see if the issue resolves. Monitor resource usage with docker stats for a running container or docker inspect for past usage.

4. Debug Application-Level Issues

If glibc/musl incompatibility and memory limits are ruled out, the fault likely lies within your application's code or its specific dependencies.

  • Increase Logging Verbosity: Modify your application to output more detailed logs, especially around the areas where it interacts with native code or performs memory-intensive operations.
  • Reproduce Locally with Debugger: Try to reproduce the issue outside Docker, or within a non-Alpine container, using debugging tools like gdb (for C/C++) or built-in debuggers for other languages.
  • Static Analysis: For C/C++ or other compiled languages, use static analysis tools (e.g., Clang-Tidy, Valgrind) to identify potential memory errors in your code.
  • Review Recent Code Changes: If the segfault started recently, review the latest code changes for potential culprits.

5. Verify Dependencies and Runtime Environment

Ensure all expected shared libraries are present and compatible.

# Run a shell inside the failing container's image to inspect dependencies
# (This assumes your image has a shell like sh or bash)
docker run --rm -it my-app:latest sh

# Once inside the container, use ldd to check dynamic library dependencies
# Replace /path/to/binary with the actual path of your application's executable
ldd /path/to/binary

Example ldd Output (Problematic glibc dependency on musl):

/ # ldd /usr/local/bin/my_app_binary
        /lib/ld-linux-x86-64.so.2 (0x7f83a4c58000)
        libm.so.6 => /lib/ld-musl-x86_64.so.1 (0x7f83a4c58000) # This looks wrong!
        libc.so.6 => /lib/ld-musl-x86_64.so.1 (0x7f83a4c58000) # This looks wrong!
        ...

If ldd shows references to /lib/ld-linux-x86-64.so.2 or libc.so.6 alongside musl entries, it's a strong indicator of glibc/musl conflict. A properly built musl application would primarily show ld-musl-x86_64.so.1 as the primary linker.

6. Utilize Advanced Debugging Tools (for C/C++ applications)

For complex C/C++ applications where other methods fail, consider attaching a debugger.

Running gdb inside a Docker container requires specific capabilities and can add significant overhead. This is typically done in development or specialized debugging environments, not production.

  1. Run container with necessary capabilities:

    docker run -d --name my-debug-app --cap-add=SYS_PTRACE --security-opt seccomp=unconfined my-app:latest
    
    • --cap-add=SYS_PTRACE: Allows ptrace system calls, necessary for debugging.
    • --security-opt seccomp=unconfined: Disables seccomp filtering, which might interfere with debugger operations.
  2. Install gdb and debug symbols in the container (temporarily):

    docker exec -it my-debug-app sh
    apk add --no-cache gdb # Add gdb
    # If using a custom binary, ensure debug symbols are available (e.g., not stripped)
    
  3. Attach gdb to your process:

    # Find the PID of your application's main process
    ps aux
    
    # Attach gdb
    gdb -p <PID_of_your_app>
    

    Once attached, you can set breakpoints, examine stack traces (bt), and inspect memory to pinpoint the exact location of the segmentation fault. This is an advanced technique requiring familiarity with gdb and the application's codebase.

πŸ‘¨β€πŸ’»

Johnathon Wheeler

Senior Systems Architect & DevOps Engineer • Austin, TX

Connect on LinkedIn →

Johnathon has over 16 years of hands-on experience designing, debugging, and scaling Linux web hosting stacks, container clusters, and high-availability database architectures. Every guide on ButItWorkedLocal is independently tested against Debian 12, Ubuntu 24.04/22.04 LTS, Rocky Linux, and Docker environments to guarantee reproducibility in production.

πŸ›‘οΈ

Our Production Verification Guarantee

Encountering a bug not covered here or running a non-standard kernel configuration? Our solutions are continually refined against real production incidents. Submit an environment trace for our editorial team to replicate.