Skip to content

How to Resolve Python Jinja2 Error "ImportError: cannot import name 'escape' (or 'Markup')"

Fix the Jinja2 ImportError for escape or Markup in Python by upgrading Flask/Dash, pinning Jinja2 to v3.0.3, or updating imports to use markupsafe directly.

When working with Flask, or other Python libraries that utilize the Jinja2 templating engine, you might encounter ImportError exceptions like cannot import name 'escape' from 'jinja2' or cannot import name 'Markup' from 'jinja2'. These errors typically appear after updating packages and signify that the way escape and Markup are imported has changed in recent Jinja2 versions. Specifically, they were moved to the markupsafe library, a dependency of Jinja2.

This guide explains this change (introduced in Jinja2 v3.1.0) and provides the standard solutions to resolve these import errors.

Understanding the Error: Relocation of escape and Markup

  • escape: A function used to safely escape characters in a string for HTML output, preventing cross-site scripting (XSS) vulnerabilities.
  • Markup: A class representing a string that is already considered "safe" for HTML output and should not be automatically escaped further by the templating engine.
  • markupsafe: A library depended upon by Jinja2 that provides the core implementation for HTML-safe string handling, including escape and Markup.

The Change in Jinja2 v3.1.0:

  • Before v3.1.0: Jinja2 re-exported escape and Markup directly from its own top-level namespace (jinja2.escape, jinja2.Markup). Code could import them directly from jinja2.
  • From v3.1.0 Onwards: Jinja2 stopped re-exporting these names directly. The canonical location to import them from is now the underlying markupsafe library.

The ImportError occurs when code (either yours or a library like an older Flask version) tries to use the old import path (from jinja2 import escape) while running with Jinja2 version 3.1.0 or newer.

Cause: Using Old Import Path with Jinja2 v3.1.0+

The direct cause is an import statement like from jinja2 import escape or from jinja2 import Markup executing in an environment where Jinja2's version is 3.1.0 or greater.

error_scenario.pypython
try:
    from jinja2 import escape
    print("Imported escape from jinja2 (unexpected).")
except ImportError as e:
    print(f"Caught expected error for escape: {e}")

try:
    from jinja2 import Markup
    print("Imported Markup from jinja2 (unexpected).")
except ImportError as e:
    print(f"Caught expected error for Markup: {e}")

If the error originates from a library you are using (most commonly Flask), the best solution is usually to upgrade that library. Newer versions of frameworks like Flask (specifically Flask v2.0.0 and later) have updated their internal code to import escape and Markup from the correct markupsafe location.

pip install --upgrade Flask

pip3 install --upgrade Flask
python -m pip install --upgrade Flask

After upgrading Flask (or other relevant libraries like Dash, etc.), the internal import errors should be resolved because the library now uses the correct import paths compatible with newer Jinja2 versions.

Solution 2: Pin Jinja2 Version to < 3.1.0 (Workaround)

If you cannot upgrade the dependent library (e.g., due to compatibility constraints with other parts of your project) or if the problematic import is in code you cannot easily change, you can force pip to install the last version of Jinja2 that did export escape and Markup directly. This is version 3.0.3.

Installing Older Jinja2 via Pip

pip uninstall Jinja2

pip install Jinja2==3.0.3 --force-reinstall

pip3 install Jinja2==3.0.3 --force-reinstall
python -m pip install Jinja2==3.0.3 --force-reinstall
  • --force-reinstall: Ensures that version 3.0.3 is installed even if a different version is already present or cached.

Pinning in requirements.txt

Add this line to your requirements.txt to ensure consistent installation across environments:

Jinja2==3.0.3

Then run pip install -r requirements.txt.

Solution 3: Update Your Code's Import Statements

If the ImportError is occurring in your own application code, modify your import statements to use markupsafe directly.


from markupsafe import escape, Markup

html_snippet = "<script>alert('xss');</script>"
safe_html = escape(html_snippet)
already_safe = Markup("<strong>This is safe</strong>")

print(f"Original: {html_snippet}")
print(f"Escaped: {safe_html}")
print(f"Markup object: {already_safe}")

This is the correct approach for your own code to be compatible with Jinja2 v3.1.0+ and reflects the library's structure.

General Troubleshooting: Upgrade All Packages

In complex environments, conflicts might arise from multiple outdated packages. While sometimes risky (it can break compatibility), upgrading all packages might resolve transitive dependency issues.

  • Method 1: Using pip-review (install first: pip install pip-review)

    pip-review --auto
  • Method 2: Script (use with extreme caution - test thoroughly!)

    import pkg_resources
    from subprocess import call
    packages = [dist.project_name for dist in pkg_resources.working_set]
    print(f"Attempting to upgrade: {' '.join(packages)}")
    call("pip install --upgrade " + ' '.join(packages), shell=True)

Recommendation: Prefer upgrading key frameworks (Flask, Dash) first (Solution 1). Only resort to upgrading everything if specific upgrades fail and you understand the potential risks. Always use a virtual environment.

Verifying Versions (pip show)

After applying a solution, check the installed versions:

pip show Jinja2
pip show markupsafe
pip show Flask # Or other relevant dependent library

Conclusion

The ImportError: cannot import name 'escape' or 'Markup' from 'jinja2' is caused by API changes in Jinja2 version 3.1.0, where these utilities were moved solely to the markupsafe library.

The primary solutions are:

  1. Upgrade Dependent Libraries: Update frameworks like Flask (to v2.0+) or Dash, which have adapted to the new import locations. This is the preferred solution.
  2. Pin Jinja2: If dependencies cannot be upgraded, pin Jinja2 to 3.0.3 (pip install Jinja2==3.0.3) or add Jinja2==3.0.3 to requirements.txt. This is a workaround.
  3. Fix Your Own Imports: If the error is in your code, change from jinja2 import escape to from markupsafe import escape (similarly for Markup).

Using virtual environments helps manage these dependencies effectively and avoid conflicts.

Navigation