ImportError: cannot import name url_quote from werkzeug.urls
Replace from werkzeug.urls import url_quote with standard library from urllib.parse import quote (or upgrade outdated extensions like Flask-Login / Flask-RESTful to versions compatible with Werkzeug 3.0+).
Root Cause Analysis
This error occurs when Python tries to import the deprecated helper function url_quote from the werkzeug.urls module, but Werkzeug 3.0+ has permanently removed this legacy wrapper in favor of Python standard library utilities.
Evolution of URL Utilities in Werkzeug
In earlier versions of Werkzeug (< 2.3.0), the package provided aliases such as url_quote, url_unquote, url_encode, and url_decode inside werkzeug.urls to support Python 2/3 cross-compatibility. Starting with Werkzeug 2.3.0, these functions were formally deprecated with warnings, and Werkzeug 3.0.0 (released alongside Flask 3.0) completely removed them from the codebase.
How the Issue Surfaces
- Outdated Third-Party Flask Extensions: Older versions of packages like
Flask-Login(< 0.6.3),Flask-JWT-Extended(< 4.5.3), orFlask-RESTXhad hardcodedfrom werkzeug.urls import url_quoteimports. - Unpinned Dependency Installation: Running
pip install flaskwithout version pins in existing environments pulls Werkzeug 3.x, breaking legacy internal utility modules. - Direct Legacy Imports in Project Code: Codebases written for Python 2/3 transition eras that relied on Werkzeug instead of the standard library
urllib.parsemodule.
Reproduction Code (MCVE)
# In Werkzeug 3.0+, url_quote was completely removed from werkzeug.urls
from werkzeug.urls import url_quote
print(url_quote('https://pythonfix.dev/query?name=test value'))
Solution 1: Migrate to Python Standard Library `urllib.parse.quote`
Replace the removed Werkzeug import with Python's built-in urllib.parse.quote function, which provides identical encoding semantics with zero external dependencies.
import urllib.parse
# Direct drop-in replacement using Python's standard library
raw_url = 'https://pythonfix.dev/search?q=flask & python'
safe_encoded_url = urllib.parse.quote(raw_url, safe=':/?&=')
print(f'Successfully encoded URL: {safe_encoded_url}')
Solution 2: Use `urllib.parse.quote_plus` and `urlencode` for Query Dictionaries
For form data and query parameters where spaces must be encoded as +, use quote_plus or urlencode.
from urllib.parse import quote_plus, urlencode
# Encoding individual query components
query_param = quote_plus('user input with spaces & symbols')
print(f'Encoded query parameter: {query_param}')
# Encoding entire query dictionaries cleanly
params = {'search': 'flask 3.0', 'page': 1, 'filter': 'active'}
encoded_query_string = urlencode(params)
print(f'Encoded query string: {encoded_query_string}')
Common Pitfalls & Migration Guidance
A common workaround attempted by developers is pinning werkzeug<3.0.0 in requirements.txt. While this temporarily resolves the ImportError, it blocks essential security patches and causes conflicts with Flask 3.0+ which requires Werkzeug 3.0+. The correct long-term fix is updating dependent packages (e.g. pip install --upgrade flask-login werkzeug) and refactoring project code to standard library urllib.parse.
Contrast with similar errors:
ModuleNotFoundError: No module named 'werkzeug.urls'vsImportError: cannot import name 'url_quote': The former occurs if Werkzeug is uninstalled or misspelled, whereas the latter confirmswerkzeug.urlsexists but the specific symbol was removed.url_quotevsurl_quote_plus:quoteencodes spaces as%20(standard for URL paths), whilequote_plusencodes spaces as+(standard for application/x-www-form-urlencoded query strings).