Exit Code 255 (Exit Out of Range) in Docker & Kubernetes
Exit code 255 has two common meanings. A process that returns -1 or calls exit(-1) appears to its parent as 255 because the status is truncated to 8 bits. The OpenSSH client also uses 255 for its own fatal errors. Neither is a Linux signal and 128+n does not apply.
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}'SSH transport
ssh -vvv -o BatchMode=yes -o ConnectTimeout=5 user@host true; echo "exit=$?"If the container produced normal application logs and then returned 255, the program chose that status. If there are no remote logs at all, suspect ssh or another transport wrapper. The transport's stderr, not the remote application log, contains the reason for a 255 that happened before the session started.
Three production root causes
Either an application returned -1, which truncates to 255, or the ssh client reported a fatal transport error. Check whether the process ran at all: an ssh failure never reached the remote command. Read ssh -vvv for the first connection or authentication error.
1. ssh could not connect or authenticate
DNS failure, TCP reset, a changed host key, a rejected key, wrong permissions on ~/.ssh, a missing ProxyJump or a server that closed the session all produce 255. The remote command never ran, so remote logs are empty. Use ssh -vvv and fix the first transport-level error rather than retrying in a loop.
2. The application returns -1 as a generic failure
C code returning -1 from main, a wrapper that propagates a negative status, or a language binding that maps every error to -1 produces 255 after the 8-bit truncation. This looks like an SSH failure only if the command is remote; check whether the process itself logged a failure first.
3. docker exec or kubectl exec propagated 255
When the exec itself succeeds, both commands propagate the remote command's exit status. A command that returns 255 is not a transport failure of kubectl or Docker; if the exec cannot start or connect, the failure is reported separately. Capture the command's own stderr and exit code, then decide whether the failure came from the executable or from the API connection.
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.
docker-compose.yml
A program that returns -1 will be restarted forever by restart: always. Fix the status mapping in the application, then use on-failure with a bounded retry count for genuinely transient failures.
services:
app:
image: ghcr.io/acme/app:1.4.2
restart: on-failure:3
stop_grace_period: 10s
deploy:
resources:
limits:
memory: 256M
reservations:
memory: 128M
deployment.yaml
Kubernetes records the container's status verbatim. 255 is not a kubelet-generated code, so read the application's own log and the exit path. If a Job wrapper runs ssh, the job fails with 255 and the remote logs are the only useful source.
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: "100m"
memory: "128Mi"
limits:
cpu: "500m"
memory: "256Mi"
Fail fast and keep the transport error visible
Retries hide the first fatal error; verbose mode shows it once.
Host deploy
HostName deploy.internal
User deploy
IdentityFile ~/.ssh/deploy_ed25519
IdentitiesOnly yes
BatchMode yes
ConnectTimeout 5
ServerAliveInterval 15
ServerAliveCountMax 3Frequently asked questions
Why does ssh return 255?
The ssh client uses 255 for its own fatal errors: connection failure, host key mismatch, authentication failure or a broken session. The remote command never ran. Run ssh -vvv, fix the first error in the transport log, and do not treat 255 as the remote program's exit status.
Why did a program that returns -1 show exit code 255?
POSIX exit statuses are 8 bits. -1 is 0xFF, which the parent observes as 255. The process did run and fail; this is different from ssh, where 255 means the client could not establish the session. Check whether the application logged an error before exiting.
How do I distinguish ssh failure from application failure?
If there are no remote logs and ssh's stderr shows a connection or authentication error, the transport failed. If the remote command logged normal output and then returned 255, the program chose that status. In CI, capture ssh's stderr separately from the remote command's stdout and stderr.
Related exit codes, signals and network references
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