Fix AWS Elastic Beanstalk Deploy Failed: WSGIPath Does Not Exist & Health Check Severe

intermediateโ˜๏ธ AWS2026-04-21| AWS Elastic Beanstalk, Python (Django/Flask), Amazon Linux 2 / Amazon Linux 2023, EB CLI 3.x

Error Message

ERROR: Your WSGIPath refers to a file that does not exist. / Instance deployment failed. For details, see 'eb-engine.log'. / Environment health has transitioned from Ok to Severe
#aws#elastic-beanstalk#health-check#deploy#eb-engine#wsgi

The Error

You pushed a new version to Elastic Beanstalk and the deployment cratered. The EB console flips to Severe, and the events log is spitting out something like:

ERROR: Your WSGIPath refers to a file that does not exist.
Instance deployment failed. For details, see 'eb-engine.log'.
Environment health has transitioned from Ok to Severe

Often this comes bundled with load balancer health check failures โ€” the LB keeps hitting your instances, gets nothing but errors back, and EB marks them unhealthy. The environment spirals from Ok โ†’ Warning โ†’ Severe in under two minutes.

Two separate problems, but they're linked. Fix the WSGI misconfiguration first. The health check failures almost always sort themselves out once the app actually starts.

Why This Happens

EB needs to know where your WSGI callable lives. It looks for this via .ebextensions, a Procfile, or the aws:elasticbeanstalk:container:python namespace. If that path doesn't match what's in your deployment zip, the app server โ€” Apache + mod_wsgi on Amazon Linux 2, or gunicorn on AL2023 โ€” never starts.

The usual culprits:

  • WSGIPath still points to application.py, but you renamed or restructured the project
  • Django project deployed without setting the path to myproject/wsgi.py
  • .ebignore or .gitignore is silently excluding the wsgi file from the bundle
  • CI/CD packaging mistake โ€” the zip uploaded to S3 is missing the file entirely
  • Health check path returns a redirect (301/302) or an auth wall instead of 200

Step 1 โ€” Read the Logs Before Touching Anything

Guessing wastes deploys. Pull the logs first:

# Via EB CLI
eb logs

# Or stream in real time
eb logs --stream

Focus on two files: eb-engine.log shows exactly which path EB tried to load. web.stdout.log shows what happened when the app server actually tried to start โ€” import errors, missing environment variables, that sort of thing.

Prefer clicking? Go to Environment โ†’ Logs โ†’ Request Logs โ†’ Last 100 Lines in the console.

Step 2 โ€” Fix the WSGIPath

Check what path EB is currently configured to use:

eb config

This opens your environment config in an editor. Find this section:

aws:elasticbeanstalk:container:python:
  WSGIPath: application:application

The format is module_path:callable for a Python object, or a plain file path for Django's wsgi.py. Here's what the correct value looks like for common setups:

Flask (single file)

# application.py contains: app = Flask(__name__)
aws:elasticbeanstalk:container:python:
  WSGIPath: application:app

Django

aws:elasticbeanstalk:container:python:
  WSGIPath: myproject/wsgi.py

Swap myproject for your actual Django project folder โ€” the one that has settings.py in it, not the repo root.

The cleanest way to manage this is version-controlling it in .ebextensions/python.config:

option_settings:
  aws:elasticbeanstalk:container:python:
    WSGIPath: myproject/wsgi.py
    NumProcesses: 1
    NumThreads: 15

That way the correct path ships with every deploy, and you're not relying on environment config that someone might accidentally overwrite.

For Django, also make sure the settings module is set:

eb setenv DJANGO_SETTINGS_MODULE=myproject.settings

Step 3 โ€” Verify the File Is Actually in the Deployment Bundle

When you run eb deploy, EB zips your project using git โ€” which means it respects .gitignore. If the wsgi file isn't tracked, it doesn't ship.

# Check what EB would actually include
git ls-files | grep wsgi

No output? The file isn't tracked. Either commit it, or override the exclusion with .ebignore:

# .ebignore โ€” force-include even if .gitignore excludes it
!myproject/wsgi.py

Building a zip manually in CI/CD? Verify its contents directly:

unzip -l deploy.zip | grep wsgi

This catches a surprisingly common CI mistake where the packaging step runs from the wrong directory and produces a zip with the wrong structure inside.

Step 4 โ€” Fix the Health Check Path

The app might be running fine, but the load balancer still marks instances unhealthy. By default, EB hits / every 30 seconds. If that path redirects (say, to a login page) or returns anything other than 2xx, the check fails.

Add a dead-simple health endpoint that always returns 200:

# Flask
@app.route('/health')
def health():
    return 'OK', 200
# Django (urls.py)
from django.http import HttpResponse

urlpatterns = [
    path('health/', lambda request: HttpResponse('OK')),
    # ... rest of your urls
]

Then point EB at it. In the console: Configuration โ†’ Load Balancer โ†’ Processes โ†’ Health check path โ†’ /health.

Or in .ebextensions:

option_settings:
  aws:elasticbeanstalk:application:
    Application Healthcheck URL: /health

Step 5 โ€” Redeploy and Watch

eb deploy --staged

Tail the events as it runs:

eb events -f

Deployment succeeded but health is still Severe? Wait it out โ€” EB requires several consecutive successful health checks (typically 3 in a row, ~90 seconds apart) before flipping back to Ok.

Verification

You're done when all three of these are true:

  • Console shows Health: Ok (green)
  • eb status reports Health: Green
  • The app URL responds correctly
eb status
# Expected:
# Environment details for: your-env-name
#   Status: Ready
#   Health: Green
curl -I https://your-env.elasticbeanstalk.com/health
# Expected: HTTP/1.1 200 OK

Quick Reference โ€” Common WSGIPath Values

  • Flask (application.py โ†’ app): application:app
  • Flask (application.py โ†’ application): application:application
  • Django: myproject/wsgi.py
  • FastAPI with Mangum: main:handler (though FastAPI typically runs on Lambda, not EB)

Still Failing? SSH In

If everything above checks out and deploys still die, go straight to the instance:

eb ssh

# Check the app server process
sudo systemctl status web

# Read the engine log directly
sudo tail -50 /var/log/eb-engine.log

Nine times out of ten, what you'll find is a missing environment variable โ€” SECRET_KEY for Django is the classic example. The app crashes on startup, never serves a single request, and EB reports the whole thing as a health check failure. The real error is buried in web.stdout.log, not the health check events.

Related Error Notes