Flask Troubleshooting
Introduction
Flask errors often look cryptic until you know the pattern—wrong virtual environment, missing template, CSRF failure, or Nginx returning 502 while Gunicorn is down. This chapter maps common symptoms to causes and fixes, with links back to the chapters where each topic is taught in depth.
Prerequisites
- You have built at least one Flask app locally—see Your First Flask Application
- Basic terminal and log reading
Diagnostic Flow
Error message → classify (install / code / DB / deploy) → check logs → fix one layer at a time| Layer | Where to look |
|---|---|
| Local dev | Terminal running flask run |
| Gunicorn | journalctl -u flask-app, error log file |
| Nginx | /var/log/nginx/error.log |
| Database | MySQL error log, app traceback |
Installation and Import Errors
ModuleNotFoundError: No module named 'flask'
Cause: Virtual environment not activated, or Flask installed globally while you run another Python.
Fix:
source .venv/bin/activate
pip install -r requirements.txt
which python
python -c "import flask; print(flask.__version__)"See Flask Environment and Installation.
ImportError: cannot import name 'create_app'
Cause: Circular import, wrong package path, or FLASK_APP pointing at wrong module.
Fix:
- Import blueprints inside
create_app, not at top of__init__.py - Use
extensions.pyfordb,login_manager - Set
FLASK_APP=app:create_apporwsgi:app
See Blueprints and Application Factory.
Server and Port Issues
Address already in use (Port 5000 or 8000)
Cause: Previous flask run or Gunicorn still bound to the port.
Fix:
# macOS / Linux
lsof -i :5000
kill <PID>
# Or use another port
flask run --port 5001On Linux servers:
ss -tlnp | grep 8000flask: command not found
Cause: venv not active or Flask not installed in current env.
Fix: Activate venv; pip install Flask.
Templates and Static Files
jinja2.exceptions.TemplateNotFound
Cause: Wrong path, typo in render_template('blog/index.html'), or templates not next to app root.
Fix:
- Confirm
templates/folder exists - Factory app:
Flask(__name__)where__name__is packageapp - Blueprint: set
template_folderif templates live inside blueprint package
See Jinja2 Templates.
CSS/JS 404 in browser
Cause: Wrong url_for('static', filename=...), file not in static/, or Nginx alias path wrong in production.
Fix:
- Dev: file under
app/static/css/style.css - Prod: Nginx
location /static/aliasmatches deploy path—deployment chapter
Forms and CSRF
CSRF token missing / The CSRF token is invalid
Cause: Form POST without {{ form.hidden_tag() }} or missing SECRET_KEY.
Fix:
<form method="post">
{{ form.hidden_tag() }}
...
</form>app.config["SECRET_KEY"] = "stable-dev-key"Tests may disable WTF_CSRF_ENABLED in TestingConfig only.
See Forms and Flask-WTF.
request.form empty on POST
Cause: Missing method="post", wrong field name, or reading request.json instead of form.
See The Request Object.
Database Errors
sqlalchemy.exc.OperationalError: connection refused
Cause: MySQL not running, wrong host/port, firewall, or bad DATABASE_URL.
Fix:
sudo systemctl status mysql
mysql -u flask -p -h 127.0.0.1 flask_appCheck URI:
mysql+pymysql://user:password@127.0.0.1:3306/dbname?charset=utf8mb4See Flask-SQLAlchemy and Models and MySQL troubleshooting.
Unknown column / no such table
Cause: Model changed but migration not applied.
Fix:
flask db migrate -m "describe change"
flask db upgradeNever rely on db.create_all() alone in production—Flask-Migrate chapter.
Garbled Unicode (emoji, Chinese)
Cause: MySQL charset not utf8mb4.
Fix: Database, table, and connection string charset—MySQL configuration.
Authentication
Redirect loop on login
Cause: Login view has @login_required, or login_view points to wrong endpoint.
Fix: Login route must be public; login_manager.login_view = "auth.login" must match blueprint endpoint name.
See Flask-Login chapter.
401 on API with JWT
Cause: Missing Authorization: Bearer <token>, expired token, or wrong JWT_SECRET_KEY between restarts.
See JWT chapter.
CORS (Browser Only)
Access-Control-Allow-Origin blocked
Cause: SPA on different port; Flask did not send CORS headers.
Fix: Flask-CORS for /api/*, or Vite dev proxy—CORS chapter.
Note: curl and Postman ignore CORS—if they work but browser fails, it is CORS.
Production and Nginx
502 Bad Gateway
Cause: Gunicorn not running, wrong proxy_pass port, or socket permissions.
Fix:
sudo systemctl status flask-app
curl http://127.0.0.1:8000/health
sudo nginx -tMatch Nginx proxy_pass http://127.0.0.1:8000 to Gunicorn bind address.
See Deploying With Gunicorn and Nginx.
504 Gateway Timeout
Cause: Slow view, worker timeout, or Nginx proxy_read_timeout too low.
Fix: Optimize query; increase Gunicorn --timeout and Nginx read timeout.
App works locally, fails on server
Checklist:
-
DEBUG=Falsebut secrets set in env file - Migrations applied on server
- Same Python version and
requirements.txtpinned - File permissions (
www-dataowns app dir)
Security-Related Surprises
Session resets every request
Cause: SECRET_KEY changes on each deploy without stable env var.
Fix: Persistent SECRET_KEY in /etc/flask-app/env.
Debugger PIN exposed
Cause: DEBUG=True on public server.
Fix: Turn off debug immediately—security chapter.
Quick Reference Table
| Symptom | Likely cause | First action |
|---|---|---|
| No module flask | venv | Activate + pip install |
| TemplateNotFound | path/name | Check templates/ tree |
| CSRF error | missing token | hidden_tag() |
| 502 | Gunicorn down | systemctl status |
| Static 404 | Nginx alias | Fix location /static/ |
| DB connection | MySQL/URI | Test mysql CLI |
| CORS browser | headers | Flask-CORS or proxy |
| Circular import | factory | Lazy blueprint import |
FAQ
Where is the full traceback?
Dev: terminal or browser debug page. Prod: Gunicorn error log + app.logger.exception.
Enable Flask debug temporarily?
Only on localhost—never on 0.0.0.0 facing internet.
pytest passes, manual test fails?
Different config—confirm TestingConfig vs DevelopmentConfig.
Docker container exits immediately?
docker logs <container>—often missing env var or migration failure in CMD.
Still stuck?
Minimal repro: one route + one template; add complexity back until it breaks—bisect the problem.
Report doc typo?
Contribute via Git fork workflow.