pallets/flask · error · TypeError

{e}\nThe view function did not return a valid response. The

Error message

{e}\nThe view function did not return a valid response. The return type must be a string, dict, list, tuple with headers or status, Response instance, or WSGI callable, but it was a {type(rv).__name__}.

What it means

Raised when Flask attempts to coerce a callable/WSGI response via Response.force_type and that raises a TypeError. The original TypeError message is prepended with guidance listing accepted return types, so the developer sees both the underlying cause and the contract.

Source

Thrown at src/flask/app.py:1339

                # special logic
                rv = self.response_class(
                    rv,  # pyright: ignore
                    status=status,
                    headers=headers,  # type: ignore[arg-type]
                )
                status = headers = None
            elif isinstance(rv, (dict, list)):
                rv = self.json.response(rv)
            elif isinstance(rv, BaseResponse) or callable(rv):
                # evaluate a WSGI callable, or coerce a different response
                # class to the correct type
                try:
                    rv = self.response_class.force_type(
                        rv,  # type: ignore[arg-type]
                        request.environ,
                    )
                except TypeError as e:
                    raise TypeError(
                        f"{e}\nThe view function did not return a valid"
                        " response. The return type must be a string,"
                        " dict, list, tuple with headers or status,"
                        " Response instance, or WSGI callable, but it"
                        f" was a {type(rv).__name__}."
                    ).with_traceback(sys.exc_info()[2]) from None
            else:
                raise TypeError(
                    "The view function did not return a valid"
                    " response. The return type must be a string,"
                    " dict, list, tuple with headers or status,"
                    " Response instance, or WSGI callable, but it was a"
                    f" {type(rv).__name__}."
                )

        rv = t.cast(Response, rv)
        # prefer the status if it was provided
        if status is not None:

View on GitHub (pinned to 3596b1ab61)

Solutions

  1. Return a Response object directly instead of a raw WSGI callable.
  2. Ensure the callable conforms to PEP 3333 (yields bytes, status/headers set).
  3. Pin compatible Werkzeug/Flask versions if a BaseResponse mismatch is the cause.

Example fix

// before
@app.route('/x')
def x():
    return some_broken_wsgi_callable  # force_type raises TypeError
// after
from flask import Response
@app.route('/x')
def x():
    return Response('ok', status=200)
Defensive patterns

Strategy: validation

Validate before calling

def to_response(rv, response_class):
    if isinstance(rv, (str, bytes, bytearray)):
        return response_class(rv)
    return response_class.force_type(rv, request.environ)

Type guard

from collections.abc import Callable
def is_acceptable_callable(rv) -> bool:
    return callable(rv) or hasattr(rv, '__call__')

Try / catch

try:
    rv = response_class.force_type(value, environ)
except TypeError:
    rv = Response('Internal type error', status=500)

Prevention

When it happens

Trigger: A view returns a callable or BaseResponse subclass that force_type cannot convert (e.g. a generator-based WSGI callable that itself errors, or a BaseResponse from an incompatible library version).

Common situations: Returning a custom WSGI callable that yields non-byte values; mixing Werkzeug versions where BaseResponse API differs; returning an object whose __call__ raises TypeError.

Related errors


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