Fix Heroku H10 App Crashed for Django
Fix Heroku H10 App crashed errors for Django apps: read the crash in heroku logs, fix the Procfile and gunicorn command, bind to $PORT, set config vars like SECRET_KEY and DATABASE_URL, and handle release-phase failures.
Problem statement
The Heroku app shows "Application error" and the router logs:
heroku[router]: at=error code=H10 desc="App crashed" method=GET path="/" host=myapp.herokuapp.com
H10 means the web dyno is not running: it started, crashed, and Heroku's restart attempts failed too. The H10 line itself never contains the reason. The cause is a few lines earlier in the logs, in the dyno's own output: a traceback from Django, a Gunicorn error, or a "process exited with status" message.
- Run
heroku logs --tail(or--num 300) and scroll to the first traceback afterStarting process. - Check the
Procfile:web: gunicorn config.wsgi --log-file -with your real project module. - Make sure
gunicornis inrequirements.txt. - Set required config vars:
SECRET_KEY,DATABASE_URL(via the Postgres add-on),ALLOWED_HOSTS,DJANGO_SETTINGS_MODULE. - Gunicorn binds to
$PORTautomatically on Heroku; do not hard-code--bind 127.0.0.1:8000. - Restart with
heroku restartafter fixing, and watch the logs.
Step-by-step solution
1. Find the real error
heroku logs --tail --app myapp
heroku ps --app myapp
Look for the sequence after a restart:
heroku[web.1]: Starting process with command `gunicorn mysite.wsgi`
app[web.1]: ModuleNotFoundError: No module named 'mysite'
heroku[web.1]: Process exited with status 3
heroku[web.1]: State changed from starting to crashed
heroku ps shows crashed for the web dyno. Run the process interactively to see full output:
heroku run python manage.py check --deploy --app myapp
2. Fix the Procfile and Gunicorn command
The Procfile lives in the repository root, named exactly Procfile with no extension:
web: gunicorn config.wsgi --log-file -
release: python manage.py migrate --noinput
config.wsgi must match the package containing wsgi.py. A project created with django-admin startproject mysite uses mysite.wsgi. If manage.py is in a subdirectory, use --chdir:
web: gunicorn --chdir backend config.wsgi --log-file -
bash: gunicorn: command not found in the logs means gunicorn is missing from requirements.txt.
3. Set config vars
Production settings that read the environment need Heroku config vars:
heroku config:set SECRET_KEY="$(python -c 'import secrets; print(secrets.token_urlsafe(50))')" --app myapp
heroku config:set DJANGO_SETTINGS_MODULE=config.settings.production ALLOWED_HOSTS=myapp.herokuapp.com --app myapp
heroku addons:create heroku-postgresql:essential-0 --app myapp # sets DATABASE_URL
heroku config --app myapp
ImproperlyConfigured or KeyError: 'SECRET_KEY' in the logs points here.
4. Bind to $PORT
Heroku assigns the port in the PORT environment variable, and Gunicorn reads it automatically. A Procfile with --bind 127.0.0.1:8000 or a settings file that starts its own server ignores it, and the dyno fails with Error R10 (Boot timeout) -> Web process failed to bind to $PORT within 60 seconds of launch, followed by H10s.
5. Release phase and build issues
If the release phase (release: python manage.py migrate) fails, the new release is not deployed and the old one keeps running, so that alone does not cause H10. But a release that deploys code requiring a migration that failed can crash on startup. Check heroku releases and heroku releases:output.
collectstatic failures happen at build time and stop the deploy; see Fix collectstatic Errors in Django.
Verification check:
heroku ps --app myapp # web.1: up
curl -sI https://myapp.herokuapp.com | head -1
heroku logs --num 50 --app myapp | grep -c H10
Explanation
Heroku's router forwards requests to running web dynos. When the web process exits, Heroku restarts it, and after repeated quick failures it backs off, leaving the dyno in a crashed state. The router has nothing to forward to and records H10 for each request. Because the router and the dyno log to the same stream, the dyno's exit reason sits just above the H10 lines, but it is easy to miss when the log is flooded with H10s from incoming traffic.
Edge cases / notes
- Memory. R14 and R15 errors (memory quota exceeded) can lead to crashes on small dynos; reduce Gunicorn workers with
WEB_CONCURRENCY. - Python version. A
.python-versionorruntime.txtnaming an unsupported version fails the build, not the boot. - Stack upgrades. Moving to a new Heroku stack can break compiled dependencies; rebuild and check logs.
- H14 means no web dynos are running at all; scale with
heroku ps:scale web=1.
Next steps
- Review the full setup in Deploy Django on Heroku.
- If requests time out instead, see Fix Heroku H12 Request Timeout in Django.
FAQ
What does Heroku H10 mean?
The web dyno crashed and is not running, so the router cannot serve requests.
Where is the real error?
In the dyno log lines before the H10 entries, after Starting process with command.
Do I need to set --bind for Gunicorn on Heroku?
No. Gunicorn reads the PORT variable automatically. Hard-coding a bind address causes boot timeouts.
How do I restart after fixing?
Deploy the fix or run heroku restart, then watch heroku logs --tail.