learntodeploy / Learn / Deployment Troubleshooting

Deployment Troubleshooting

Diagnose and fix failed deployments — Last updated: September 2026

Deployment troubleshooting is the skill of figuring out why a deployment failed and fixing it. A deployment can fail at any stage — the build might not produce an artifact, the container might not start, the health check might fail, the service might be unreachable. Each failure mode has a different cause and a different diagnostic path.

The key to troubleshooting is a systematic process: read the logs, check the state of the running service, verify the configuration, form a hypothesis, test it, and fix the root cause — not just the symptom. Guessing and redeploying without understanding the problem usually makes it worse.

The deployment simulator at LearnToDeploy includes deployment failures that you diagnose and fix — wrong ports, missing environment variables, broken health checks, failed builds. Each one is a realistic problem with a real diagnostic path.

The Troubleshooting Process

A deployment failure is a symptom. The service is not responding, the health check is failing, the container is crashing. The symptom tells you something is wrong; it does not tell you why. Troubleshooting is the process of finding the cause.

A systematic approach

A common mistake is to guess and redeploy without reading the logs. A redeploy that does not change anything will fail the same way. Read the logs first. The answer is usually in them.

502 Bad Gateway

A 502 Bad Gateway means the platform — the proxy, the load balancer, the ingress — cannot reach the application. The platform is up, but it cannot get a valid response from the service it is trying to route traffic to.

A 502 is a platform-level message, not an application-level one. The application might be running. It might be listening. It might be healthy by its own definition. But the platform cannot reach it, so it returns 502.

Common causes of 502

# Platform-side view: 502 from the proxy
curl -s -o /dev/null -w "%{http_code}" http://localhost:8000/health
# 502

# Check if the container is running
docker ps | grep myapp
# Check what port the app is actually listening on
docker exec myapp ss -tlnp

Connection Refused

Connection refused means the platform reached the host, but nothing was listening on the port. This is different from a timeout — the host responded, but said there is nothing at that port.

Common causes of connection refused

# Check what is actually listening
ss -tlnp | grep 8000
# If nothing is listening on 8000, the application is not bound to that port

# Check the application's configured port
grep -r "PORT" .env
grep -r "port" config.yaml
# Compare against what the platform expects

Health Check Failures

A health check is a request the platform makes to verify the service is alive. If the health check fails, the platform considers the service unhealthy and stops routing traffic to it — even if the application is running and handling some requests.

A health check failure is not always a problem with the health check itself. It is often a symptom of a deeper problem: the database is not connected, the cache is unavailable, the application is too slow to respond. The health check is reporting that the service is not healthy, and it is usually right.

What a health check verifies

# A health check that fails when the database is not connected
@app.route("/health")
def health():
    try:
        db.execute("SELECT 1")
        return {"status": "healthy"}, 200
    except Exception:
        return {"status": "unhealthy", "reason": "database"}, 503

If the health check returns 503, do not just make the health check more lenient. Find out why the database is not connected — missing environment variable, wrong host, wrong credentials — and fix that.

Missing or Wrong Environment Variables

Environment variables configure the application at runtime — database connections, ports, secret keys, API endpoints. If a required variable is missing, the application might fail to start, fail to connect to a dependency, or silently fall back to a wrong default.

Signs of a missing environment variable

# Compare the live environment against the documented example
diff .env.example .env
# Or check specific variables
echo $DATABASE_HOST
echo $PORT
echo $DATABASE_URL
The most reliable way to catch missing environment variables is to make the application fail fast when a required variable is missing — fail at startup with a clear error, not later when it tries to connect and fails.

Port Mismatches

A port mismatch is one of the most common deployment failures and one of the easiest to diagnose once you know to check for it. The application listens on one port, and the platform expects traffic on another. The application is running — it just is not reachable on the port the platform is checking.

# The application is configured to listen on 8080
# The platform expects 8000
# The container starts, the application runs, the health check fails

# Check the application's port configuration
grep -r "PORT" .env .env.example config.yaml server.py
# Check what the platform expects
grep -r "port" platform-config.yaml deployment.yaml

# The fix: make them match
PORT=8000

A port mismatch is often caused by a default that differs from the platform's expectation. The application default is 8080. The platform expects 8000. If the PORT environment variable is not set, the application uses its default — and the deployment fails.

Build Failures

A build failure means the artifact was never produced. The deployment cannot proceed because there is nothing to deploy. Build failures happen in the CI stage, before the deployment stage, and they should fail the pipeline — that is what CI is for.

Common build failures

# Read the build log — the failure is usually at the end
docker build -t myapp:latest . 2>&1 | tail -30
# Or check the CI pipeline log
# The build stage that failed is the first place to look

Practice Troubleshooting in the Simulator

The LearnToDeploy deployment simulator includes deployment failures that you diagnose and fix using the same tools you would use in a real environment: reading logs, checking environment variables, inspecting the running service, editing configuration, and verifying the fix with a health check.

Each failure in the simulator is a realistic problem — a wrong port, a missing variable, a broken health check, a container that exits immediately. The simulator gives you the logs and the tools to figure out what is wrong, and it tells you when you have fixed it — when the health check passes, the deployment is healthy.

For the concepts behind the failures, see the deployment concepts library, including entries on health checks, ports and networking, environment variables, and logs and debugging.

← Back to Learn