Troubleshooting

Fix a Docker container that exits immediately

Find out why a Docker container stops right after it starts. Read logs and exit codes, then fix missing environment variables, a wrong command, background processes and restart loops.

BeginnerLinux server5 min read

You run docker run -d or docker compose up -d, and a moment later the container shows Exited or keeps flipping to Restarting. A container lives exactly as long as its main process. When that process ends, for any reason, the container stops. This guide shows how to find the reason in a minute and fixes the usual causes.

Before you start

  • A Linux VPS with Docker Engine and Compose.
  • The name of the failing container. List all containers, including stopped ones:
Bash
docker ps -a --format 'table {{.Names}}\t{{.Status}}\t{{.Image}}'

A status such as Exited (1) 5 seconds ago or Restarting (127) 2 seconds ago tells you it has stopped and with which exit code.

Step 1: read the logs

The answer is usually in the last lines the app printed:

Bash
docker logs --tail 50 myapp

With Compose:

Bash
docker compose logs --tail 50 app

Common messages and their meaning:

  • Error: missing required environment variable DATABASE_URL: configuration is missing.
  • exec /app/start.sh: no such file or directory: wrong path or Windows line endings in a script.
  • exec format error: the image was built for a different CPU architecture.
  • ECONNREFUSED or could not connect to server: the app gives up because a dependency is not ready.

Step 2: check the exit code

Bash
docker inspect myapp --format 'ExitCode={{.State.ExitCode}} OOMKilled={{.State.OOMKilled}} Error={{.State.Error}}'

What the codes mean:

  • 0: the process finished normally. The command ran to completion, so there was nothing to keep the container alive.
  • 1 or another small number: the app hit an error. The logs explain which.
  • 125: Docker itself failed to run the container, often a bad option.
  • 126: the command was found but cannot be executed, usually a permission problem.
  • 127: the command was not found inside the image.
  • 137: the process was killed, often by the out-of-memory killer. Check OOMKilled.
  • 139: a segmentation fault inside the app.

Cause: missing environment variables

Many images need certain variables to start. For example, the official PostgreSQL image refuses to start without a password:

Bash
docker run -d --name db -e POSTGRES_PASSWORD=change-me postgres:16

Read the image's documentation on Docker Hub for required variables. In Compose, check that an env_file path is right and that the file is in the same folder as compose.yaml if you use a relative path. docker compose config shows the final values Compose will use.

Cause: the command finishes or is wrong

A container needs a process that keeps running in the foreground. These do not:

  • An image such as ubuntu or alpine with no command. Its default is a shell, which exits at once without a terminal.
  • A command that starts a service in the background, such as service nginx start, then returns.
  • A script that ends after setup.

Run servers in the foreground. For Nginx, the official image already uses nginx -g 'daemon off;'. For your own images, make the last step of a start script use exec so the app replaces the shell:

Bash
exec node server.js

To keep a test container alive while you investigate, override the command:

Bash
docker run -d --name debug myapp:1.0 sleep infinity
docker exec -it debug sh

Inside, run the real start command by hand and watch the error appear.

Cause: script problems

  • no such file or directory for a script that exists: the file has Windows (CRLF) line endings, so the #!/bin/sh line is wrong. Convert it with dos2unix or set your editor to LF.
  • permission denied running a script: make it executable before building, or add RUN chmod +x /app/start.sh in the Dockerfile.
  • /bin/bash: not found: Alpine images have no bash. Use /bin/sh.

Cause: a dependency is not ready

Apps often exit if the database is still starting. Add a health check to the database and make the app wait for it:

YAML
services:
  app:
    depends_on:
      db:
        condition: service_healthy

Add health checks to Docker containers shows the matching database checks.

Restart loops

With restart: unless-stopped or always, a crashing container restarts again and again, with a growing delay. The cause is the same as above, but logs can scroll by. Stop the loop while you debug:

Bash
docker update --restart no myapp
docker stop myapp

Fix the problem, then set the policy back with docker update --restart unless-stopped myapp or recreate it with Compose.

Check it works

After your fix, start the container and watch it for longer than ten seconds:

Bash
docker compose up -d
docker compose ps
docker compose logs -f --tail 20 app

The status should stay Up and the logs should show the app listening or ready, with no new errors.

Troubleshooting

  • Logs are empty: the process fails before printing anything. Run the image interactively with docker run --rm -it --entrypoint sh myapp:1.0 and start it by hand.
  • Exit code 137 with OOMKilled=true: raise the memory limit or reduce the app's memory use. See Limit Docker container CPU and memory.
  • exec format error: the image does not match the server's CPU. See Fix "exec format error" and image platform mismatches.
  • Works with docker run but not in Compose: compare settings with docker compose config. A different command, user or missing volume is common.

Next steps

Was this guide helpful?

Still stuck?

Ask MdmHost AI for a quick answer, or open a ticket and our team will take a look. We are here 24/7.