pallets/flask · error · TemplateNotFound

{template}

Error message

{template}

What it means

DispatchingJinjaLoader._get_source (the explanatory path) iterates the app then blueprints' jinja_loaders, attempts each, records attempts, calls explain_template_loading_attempts for debugging, and if no loader returned the template it raises TemplateNotFound(template). The message is just the template name; the real diagnostics are in the explained attempts logged before raising.

Solutions

  1. Verify the template file exists under the app's template_folder (default templates/) or the blueprint's template_folder.
  2. Enable EXPLAIN_TEMPLATE_LOADING or call explain_template_loading_attempts to see which loaders were tried.
  3. Correct the template name spelling/case and the path passed to render_template.
  4. For blueprint templates, set template_folder='templates' on the Blueprint and reference by name only.

Example fix

// before
return render_template('home.htm')  # typo

// after
return render_template('home.html')
Defensive patterns

Strategy: validation

Validate before calling

from jinja2 import TemplateNotFound

def template_exists(app, name: str) -> bool:
    try:
        app.jinja_env.get_template(name)
        return True
    except TemplateNotFound:
        return False

Try / catch

try:
    return render_template(name)
except TemplateNotFound:
    app.logger.error('template %s not found; tried loaders see EXPLAIN_TEMPLATE_LOADING', name)
    abort(404)

Prevention

When it happens

Trigger: render_template('missing.html'); render_template('sub/file.html') where the file is absent; a typo in the template name; templates folder misconfigured; blueprint template folder not set so the template is not found in any loader.

Common situations: Template file deleted or renamed; template_folder path wrong relative to the app root; case-sensitivity mismatch (especially deploying from macOS to Linux); blueprint templates expected under the wrong folder.

Related errors


AI-assisted analysis of pallets/flask@3596b1ab61 (2026-08-11). Data as JSON: /api/errors/92f2922247de286a. Report an issue: GitHub.

Appendix: source

Thrown at src/flask/templating.py:86

        rv: tuple[str, str | None, t.Callable[[], bool] | None] | None
        trv: None | (tuple[str, str | None, t.Callable[[], bool] | None]) = None

        for srcobj, loader in self._iter_loaders(template):
            try:
                rv = loader.get_source(environment, template)
                if trv is None:
                    trv = rv
            except TemplateNotFound:
                rv = None
            attempts.append((loader, srcobj, rv))

        from .debughelpers import explain_template_loading_attempts

        explain_template_loading_attempts(self.app, template, attempts)

        if trv is not None:
            return trv
        raise TemplateNotFound(template)

    def _get_source_fast(
        self, environment: BaseEnvironment, template: str
    ) -> tuple[str, str | None, t.Callable[[], bool] | None]:
        for _srcobj, loader in self._iter_loaders(template):
            try:
                return loader.get_source(environment, template)
            except TemplateNotFound:
                continue
        raise TemplateNotFound(template)

    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

View on GitHub (pinned to 3596b1ab61)