Skip to main content

Debugging Template Loading

When you encounter a TemplateNotFound error or find that the wrong template is being rendered, Flask provides a built-in debugging tool to trace exactly how it resolves template paths. Because Flask searches for templates in the application's folder first and then in every registered blueprint's folder, identifying which loader is winning (or why all are failing) can be difficult without visibility into the search process.

Enabling Template Loading Explanations

To see the sequence of attempts Flask makes to find a template, set the EXPLAIN_TEMPLATE_LOADING configuration option to True.

from flask import Flask

app = Flask(__name__)
app.config["EXPLAIN_TEMPLATE_LOADING"] = True

When this is enabled, every request that involves template rendering will log the resolution attempts to the application logger at the INFO level.

Interpreting the Resolution Log

When you attempt to render a template, the DispatchingJinjaLoader iterates through all available loaders. If EXPLAIN_TEMPLATE_LOADING is active, it uses explain_template_loading_attempts from flask.debughelpers to format the results.

Example: Missing Template

If you try to render missing.html and it cannot be found, your logs will look like this:

[INFO] Locating template 'missing.html':
1: trying loader of application 'my_app'
class: jinja2.loaders.FileSystemLoader
searchpath:
- /path/to/app/templates
-> no match
2: trying loader of blueprint 'auth' (my_app.auth)
class: jinja2.loaders.FileSystemLoader
searchpath:
- /path/to/app/blueprints/auth/templates
-> no match
Error: the template could not be found.

Example: Template Shadowing

Flask searches the application's template folder before any blueprint folders. If a blueprint and the application both have a template with the same name, the application's version will always be used. The debug log identifies this "shadowing" by warning you when multiple loaders find a match:

[INFO] Locating template 'layout.html':
1: trying loader of application 'my_app'
class: jinja2.loaders.FileSystemLoader
searchpath:
- /path/to/app/templates
-> found ('/path/to/app/templates/layout.html')
2: trying loader of blueprint 'admin' (my_app.admin)
class: jinja2.loaders.FileSystemLoader
searchpath:
- /path/to/app/blueprints/admin/templates
-> found ('/path/to/app/blueprints/admin/templates/layout.html')
Warning: multiple loaders returned a match for the template.

Resolution Order

The DispatchingJinjaLoader follows a strict order when searching for templates:

  1. Application Loader: The jinja_loader defined on the Flask app instance (usually looking in the /templates folder).
  2. Blueprint Loaders: Loaders for all registered blueprints, searched in the order they were registered via app.register_blueprint().

This order is implemented in DispatchingJinjaLoader._iter_loaders:

def _iter_loaders(self, template: str) -> t.Iterator[tuple[Scaffold, BaseLoader]]:
loader = self.app.jinja_loader
if loader is not None:
yield self.app, loader

for blueprint in self.app.iter_blueprints():
loader = blueprint.jinja_loader
if loader is not None:
yield blueprint, loader

Troubleshooting

Logs are not appearing

The template loading explanation is logged using app.logger.info. If your logging level is set to WARNING or ERROR, these messages will be suppressed even if EXPLAIN_TEMPLATE_LOADING is True. Ensure your logger is configured to show INFO messages:

import logging
logging.basicConfig(level=logging.INFO)

Blueprint templates not found

If the logs show that a blueprint's loader is being skipped or is not searching the path you expect, verify that:

  1. The blueprint was initialized with a template_folder argument (e.g., Blueprint("auth", __name__, template_folder="templates")).
  2. The blueprint has been registered on the app instance. DispatchingJinjaLoader only iterates over blueprints returned by app.iter_blueprints().
  3. The template is located within the specified folder. If you are using a blueprint named auth and your template is at auth/login.html, the file should be at blueprints/auth/templates/auth/login.html.