pallets/flask · error · TypeError

The view function did not return a valid response. The retur

Error message

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 {type(rv).__name__}.

What it means

Raised in `Flask.make_response()` (src/flask/app.py:1344) when the view's return value matches none of the supported types: it is not a str/bytes/bytearray/iterator (body), not a dict or list (JSON), not a Response/BaseResponse, and not callable. Flask cannot serialize arbitrary Python objects into an HTTP response, so it rejects the value and names the offending type.

Source

Thrown at src/flask/app.py:1344

                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:
            if isinstance(status, (str, bytes, bytearray)):
                rv.status = status
            else:
                rv.status_code = status

        # extend existing headers with provided headers
        if headers:
            rv.headers.update(headers)

View on GitHub ↗ (pinned to 6a2f545bfd)

Solutions

  1. Convert the value to a supported type: wrap objects in `jsonify(...)` or return a dict/list built from the object (e.g. `return model.to_dict()`).
  2. For a bare status code, return a tuple with an empty body: `return '', 204` — or use `abort(404)` for error statuses.
  3. Serialize non-JSON-native types (Decimal, datetime, sets) to str/list/dict before returning, or register a custom JSON provider.
  4. Return `str(value)` for simple scalar responses.

Example fix

# before
@app.route("/count")
def count():
    return Item.query.count()  # returns an int

# after
@app.route("/count")
def count():
    return {"count": Item.query.count()}  # dict is JSON-serialized
Defensive patterns

Strategy: type-guard

Type guard

from flask import Response
def is_returnable(rv) -> bool:
    return isinstance(rv, (str, bytes, dict, list, tuple, Response)) or callable(rv)

Prevention

When it happens

Trigger: Returning an int (`return 204`), bool, float, set, ORM model instance, dataclass, numpy array, or any custom object from a view. The message's `{type(rv).__name__}` tells you exactly which type was returned. Also fires for the body element of a (body, status) tuple when the body is an unsupported type.

Common situations: `return 200` or `return 404` intending a bare status code (a body is required — use `('', 404)` or `abort(404)`); returning SQLAlchemy model objects or query results expecting automatic JSON; returning a `set` (not JSON-serializable-typed here, unlike dict/list); returning a Decimal/datetime directly; forgetting `jsonify` for objects that aren't plain dicts/lists.

Related errors


AI-assisted analysis of pallets/flask@6a2f545bfd (2026-07-31). Data as JSON: /data/errors/0dd82b81aa5f6944.json. Report an issue: GitHub ↗.