pallets/flask · error · ValueError
When specifying '_scheme', '_external' must be True.
Error message
When specifying '_scheme', '_external' must be True.
What it means
Raised in `Flask.url_for()` (src/flask/app.py:1200) when `_scheme` is passed together with an explicit `_external=False`. A scheme (e.g. 'https') only appears in absolute URLs; a relative URL cannot carry one, and Flask rejects the combination explicitly to avoid silently dropping the scheme and producing accidentally insecure links.
Source
Thrown at src/flask/app.py:1200
url_adapter = self.create_url_adapter(None)
if url_adapter is None:
raise RuntimeError(
"Unable to build URLs outside an active request"
" without 'SERVER_NAME' configured. Also configure"
" 'APPLICATION_ROOT' and 'PREFERRED_URL_SCHEME' as"
" needed."
)
# When outside a request, generate a URL with scheme and
# domain by default.
if _external is None:
_external = True
# It is an error to set _scheme when _external=False, in order
# to avoid accidental insecure URLs.
if _scheme is not None and not _external:
raise ValueError("When specifying '_scheme', '_external' must be True.")
self.inject_url_defaults(endpoint, values)
try:
rv = url_adapter.build( # type: ignore[union-attr]
endpoint,
values,
method=_method,
url_scheme=_scheme,
force_external=_external,
)
except BuildError as error:
values.update(
_anchor=_anchor, _method=_method, _scheme=_scheme, _external=_external
)
return self.handle_url_build_error(error, endpoint, values)
if _anchor is not None:View on GitHub ↗ (pinned to 6a2f545bfd)
Solutions
- Remove `_external=False` — passing `_scheme` implies you want an absolute URL, and Flask will set `_external=True` for you.
- If you actually want a relative URL, drop the `_scheme` argument instead.
- To make all generated URLs https without per-call arguments, set `PREFERRED_URL_SCHEME = 'https'` in config (used outside requests) or fix your proxy headers (`X-Forwarded-Proto` with ProxyFix) so in-request URLs get the right scheme.
Example fix
# before
url = url_for("login", _scheme="https", _external=False)
# after
url = url_for("login", _scheme="https", _external=True)
# or, for a relative URL:
url = url_for("login") Defensive patterns
Strategy: validation
Validate before calling
kwargs = {'_scheme': 'https'}
if '_scheme' in kwargs:
kwargs['_external'] = True
url = url_for('index', **kwargs) Prevention
- Always pair `_scheme='https'` with `_external=True` in url_for calls
- For app-wide HTTPS, set PREFERRED_URL_SCHEME='https' instead of passing _scheme per call
- Wrap url_for in a small helper that enforces the pairing if you build external URLs in many places
When it happens
Trigger: `url_for('endpoint', _scheme='https', _external=False)`. Inside a request, passing `_scheme` alone auto-sets `_external=True` (app.py:1173-1174), so the error only fires when `_external=False` is passed explicitly alongside `_scheme`.
Common situations: Copy-pasted url_for calls where someone added `_external=False` to 'fix' full URLs appearing in links while a global helper still passes `_scheme='https'`; wrapper functions that forward both kwargs with conflicting defaults; code written for older Flask versions where `_scheme` behavior differed (pre-2.2 required `_external=True` explicitly with `_scheme`).
Related errors
- Unable to build URLs outside an active request without 'SERV
- Using "--cert" requires Python to be compiled with SSL suppo
- Using ad-hoc certificates requires the cryptography library.
- Working outside of application context. Attempted to use fu
- Working outside of request context. Attempted to use functi
AI-assisted analysis of pallets/flask@6a2f545bfd (2026-07-31).
Data as JSON: /data/errors/8d06427abfec2385.json.
Report an issue: GitHub ↗.