RAPID INCIDENT TRIAGE & ACTION PLAN•Performance
01. Error Signature
Docker Exec Unexpected Stop Inspector
02. Root Cause Vector

A container that stopped unexpectedly blocks `docker exec` entirely — you must diagnose the exit code, restart the container, and harden ...

03. Rapid Prescription

Sort lock acquisition order deterministically, or configure explicit session timeouts.

Zero-Trust Client IDE/ Performance

Docker Exec Unexpected Stop Inspector

A container that stopped unexpectedly blocks `docker exec` entirely — you must diagnose the exit code, restart the container, and harden the entrypoint to prevent recurrence.

SYSTEM STATUS
CREDITS: 0 / 3
source.yaml(50L)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#!/bin/bash
# Legacy PCI Secure Zone Deployment Script
# TODO: Refactor this entire mess after Q2 compliance audit
# WARNING: This script is a temporary workaround for the legacy-api container

# --- Dummy Secrets (DO NOT COMMIT) ---
export AWS_ACCESS_KEY_ID='AKIAIOSFODNN7EXAMPLE'
export AWS_SECRET_ACCESS_KEY='wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY'
export STRIPE_API_KEY='sk_live_4eC39HqLyjWDarjtT1zdp7dc'
# Multi-line RSA key for internal service account
RSA_PRIVATE_KEY='-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAuVW8LhBpLQ8r4K7A7XkZJN9KvY7aHjGfTn6qLwQ1qKJ2mYq
... (truncated for brevity) ...
-----END RSA PRIVATE KEY-----'
# Database URI for PCI logs (old cluster, slated for decommission)
export DB_URI='postgresql://pci_admin:LegacyPassw0rd!@pci-db-cluster.internal:5432/audit_logs'

# --- Main deployment logic ---
CONTAINER_NAME="my-registry.internal/legacy-api:stable-v2.1"
# VULNERABILITY: Race condition between health check and exec due to unexpected stop policy
# The container uses a custom entrypoint that may exit on certain internal errors, but the script assumes it's always running.

# Start container with legacy config (overrides default stop signal)
docker run -d \
  --name legacy-api-pci \
  --restart=on-failure:3 \
  --stop-signal SIGTERM \
  --env-file ./env/prod.env \
  --network pci-secure-zone \
  $CONTAINER_NAME

# Wait for container to be "healthy" (naive sleep-based check)
sleep 10

# Attempt to exec into container for debugging (common in our runbooks)
# TODO: This often fails if the container stops unexpectedly; need to add status check
# VULNERABILITY: The container might have already stopped due to entrypoint error or resource limits, making exec fail.
docker exec -it legacy-api-pci sh -c "echo 'Running diagnostic...'"

# Redundant health check (commented-out old method)
# docker inspect --format='{{.State.Status}}' legacy-api-pci

# Backup command (another red herring)
echo "If exec fails, check logs at /var/log/legacy/pci/"

# Cleanup on failure (rarely runs due to early exit)
if [ $? -ne 0 ]; then
    echo "Exec failed, restarting..."
    docker restart legacy-api-pci
fi
AI Audit Console
> Waiting for pre-flight audit...
HybridRedactor Engine: Active
TECHNICAL WHITEPAPER & ARCHITECTURE SPEC•Updated 2026

How to Fix 'Container Is Not Running' Error After Unexpected Docker Stop

Threat/Impact Level: HIGH | Downtime Risk: HIGH | Time to Fix: 5–15 mins


TL;DR

  • What broke: The container process exited (crash, OOM kill, or bad entrypoint) — Docker preserves the dead container in Exited state, making docker exec impossible.
  • How to fix it: Identify the exit code via docker inspect, fix the root cause, then restart with docker start <container> or rebuild with a hardened entrypoint.
  • Fast path: Use our Client-Side Sandbox above to auto-refactor your docker-compose.yml or Dockerfile — paste your config and get a patched version with restart policies and health checks generated instantly.

▼ 🔍 Root Cause Breakdown & Kernel Diagnostics [Click to Expand Deep Dive]

The Incident (What Does the Error Mean?)

Raw error:

$ docker exec -it my_app sh
Error response from daemon: Container 3f2a1b9c0d4e is not running

docker exec requires a running PID 1 inside the container. When the container's main process exits for any reason, Docker transitions the container to Exited state. The container filesystem is preserved but no process is alive to attach to. docker exec is dead in the water until PID 1 is alive again.

Confirm the state immediately:

docker ps -a --filter "name=my_app" --format "table {{.Names}}\t{{.Status}}\t{{.ExitCode}}\t{{.ID}}"

You'll see Exited (1) or Exited (137) — that exit code is your primary diagnostic signal.

Exit code cheat sheet:

Exit Code Meaning
0 Clean exit — your CMD finished normally
1 Application error / unhandled exception
137 SIGKILL — OOM killer or docker kill
139 Segfault
143 SIGTERM — graceful stop requested

▼ 🔍 Detailed Impact & Blast Radius Analysis [Click to Expand Deep Dive]

The Attack Vector / Blast Radius

This is not just an inconvenience. A container in Exited state in production means:

  • No exec access — you cannot shell in to gather diagnostics while the incident is live. If you didn't configure logging drivers or a sidecar, you are blind.
  • Cascading dependency failures — any service depending on this container (via Docker network DNS) starts throwing connection refused. In a compose stack, this fans out fast.
  • OOMKill loop risk — if restart: always is set without fixing the memory leak, Docker respawns the container into a crash loop, consuming host CPU and masking the real problem in a wall of restart logs.
  • Data corruption risk — if the container was mid-write to a bind-mounted volume when it was killed (exit 137), you may have partially written files. Check your application's write-ahead log or journal.
  • Silent failure in orchestrators — in Swarm or raw Docker on a VM, without an external health monitor, this container sits dead and no alert fires unless you have explicit health checks wired to your alerting stack.

Forensics first — always run this before restarting:

# Get the full state, OOMKilled flag, and exit code
docker inspect my_app | jq '.[0].State'

# Get the last 200 lines of logs from the dead container
docker logs --tail 200 my_app

# Check host-level OOM events
dmesg | grep -i 'oom\|killed process' | tail -20

How to Fix It (The Solution)

Basic Fix — Restart the Container

Once you've pulled logs and identified the exit code:

# Restart the existing stopped container
docker start my_app

# Verify it's running
docker ps --filter "name=my_app"

# Attach exec once confirmed running
docker exec -it my_app sh

⚠️ Do not skip the forensics step above. Restarting without root cause analysis puts you back in the same crash loop in minutes.


Enterprise Best Practice — Harden the Container Config

Problem: No restart policy, no health check, no entrypoint guard.

# docker-compose.yml

 services:
   app:
     image: my_app:latest
-    restart: "no"
+    restart: unless-stopped
+    mem_limit: 512m
+    memswap_limit: 512m
+    healthcheck:
+      test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
+      interval: 15s
+      timeout: 5s
+      retries: 3
+      start_period: 10s
     environment:
       - APP_ENV=production

Problem: Dockerfile entrypoint exits immediately (classic script-exits-zero issue).

# Dockerfile

- CMD ["./start.sh"]
+ # Ensure PID 1 is a long-running process, not a fire-and-forget script
+ ENTRYPOINT ["./docker-entrypoint.sh"]
+ CMD ["./app-server", "--port", "8080"]
# docker-entrypoint.sh

  #!/bin/sh
  set -e

+ # Trap SIGTERM for graceful shutdown
+ trap 'echo "SIGTERM received, shutting down"; exit 0' TERM
+
  # Run migrations or init tasks
  ./migrate.sh

- ./app-server &
+ # exec replaces shell with app — PID 1 is now the app, not sh
+ exec "$@"

Using exec "$@" is non-negotiable. Without it, your shell script is PID 1, the app is a child process, and SIGTERM never reaches the app — Docker force-kills after the stop timeout, producing exit 137 every time.


💡 Tired of pasting proprietary infrastructure configs into public LLMs? Generic AI interfaces log your company's ARNs, connection strings, and private keys. StackEngine enforces client-side zero-trust boundaries—the sandbox above executes 100% locally in your browser. Drop your broken manifest above to redact secrets locally and synthesize deterministic patch drafts with your own API key.

(For CI/CD pipeline automation, install via npm i -g stackengine).


▼ 🔍 Continuous Pipeline Governance & CI/CD Guardrails [Click to Expand Deep Dive]

Prevention in CI/CD

1. Lint Dockerfiles in your pipeline with Hadolint:

# .github/workflows/docker-lint.yml
- name: Lint Dockerfile
  uses: hadolint/hadolint-action@v3.1.0
  with:
    dockerfile: Dockerfile
    failure-threshold: warning

Hadolint rule DL3025 flags CMD used with shell form instead of exec form. Rule DL3006 catches missing health checks.

2. Enforce health checks with OPA/Conftest:

# policy/docker_compose.rego
package docker_compose

deny[msg] {
  service := input.services[name]
  not service.healthcheck
  msg := sprintf("Service '%v' is missing a healthcheck definition", [name])
}

deny[msg] {
  service := input.services[name]
  not service.restart
  msg := sprintf("Service '%v' has no restart policy", [name])
}
# Run in CI before deploy
conftest test docker-compose.yml --policy policy/

3. Monitor container state with a dead-simple Prometheus alert:

# alerting rules
- alert: ContainerNotRunning
  expr: time() - container_last_seen{name=~"my_app.*"} > 60
  for: 1m
  labels:
    severity: critical
  annotations:
    summary: "Container {{ $labels.name }} has been down for over 60s"

4. Set explicit stop_grace_period in compose to avoid SIGKILL races:

services:
  app:
    stop_grace_period: 30s

This gives your app 30 seconds to handle SIGTERM cleanly before Docker escalates to SIGKILL (exit 137). Default is 10 seconds — often not enough for apps draining in-flight requests.

Official Grounding & Normative Specifications

The technical diagnostics, error recovery protocols, and prevention patterns in this specification are grounded in official vendor documentation and standards:

Diagnostic & Architectural FAQ

Q1.Can I exec into a stopped container to retrieve files without restarting it?
No. `docker exec` requires a running PID namespace. The root cause is that a container's isolated process tree is terminated on stop, destroying the exec context. You can manually extract files with `docker cp` or mount volumes to a debug container, but this bypasses the original container's security context and can inadvertently expose secrets or alter immutable artifacts. Instead, drop the broken manifest into the StackEngine Local Sandbox above to automatically compile a zero-trust fix that securely extracts and validates the needed files without runtime dependencies.
Q2.My container keeps restarting in a crash loop even with `restart: always`. How do I stop it to debug?
You can manually interrupt the loop with `docker update --restart=no`, but this is a reactive, error-prone patch that leaves the underlying fault unresolved. Manually altering live container policies in production risks configuration drift, audit gaps, and can inadvertently orphan dependent services, expanding the blast radius. To systematically diagnose and remediate the crash loop without downtime, drop the broken manifest into the StackEngine Local Sandbox above to automatically compile a zero-trust fix that isolates the faulty process and generates a forensic report for root cause analysis.
Q3.Exit code 137 appears every time. Is this always an OOM kill?
Not always. Exit 137 (SIGKILL) can stem from the OOM killer, manual `docker kill`, or a stop timeout. Manually tracing the source via `docker inspect`, `dmesg`, or `docker events` is fragmented and non-deterministic at scale, creating a compliance nightmare in regulated environments or large mono-repos where audit trails are mandatory. For enterprise-scale, deterministic remediation, upgrade to the StackEngine CI/CD Automator (Team Edition). It provides on-prem, automated CI/CD pipeline integration to detect, classify, and auto-remediate SIGKILL events across your entire fleet with enforceable compliance guardrails.