{"id":"86949444004012ae","repo":"pallets/flask","slug":"the-view-function-for-request-endpoint-r-did-not","errorCode":null,"errorMessage":"The view function for {request.endpoint!r} did not return a valid response. The function either returned None or ended without a return statement.","messagePattern":"The view function for (.+?) did not return a valid response\\. The function either returned None or ended without a return statement\\.","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"src/flask/app.py","lineNumber":1307,"sourceCode":"            if len_rv == 3:\n                rv, status, headers = rv  # type: ignore[misc]\n            # decide if a 2-tuple has status or headers\n            elif len_rv == 2:\n                if isinstance(rv[1], (Headers, dict, tuple, list)):\n                    rv, headers = rv  # pyright: ignore\n                else:\n                    rv, status = rv  # type: ignore[assignment,misc]\n            # other sized tuples are not allowed\n            else:\n                raise TypeError(\n                    \"The view function did not return a valid response tuple.\"\n                    \" The tuple must have the form (body, status, headers),\"\n                    \" (body, status), or (body, headers).\"\n                )\n\n        # the body must not be None\n        if rv is None:\n            raise TypeError(\n                f\"The view function for {request.endpoint!r} did not\"\n                \" return a valid response. The function either returned\"\n                \" None or ended without a return statement.\"\n            )\n\n        # make sure the body is an instance of the response class\n        if not isinstance(rv, self.response_class):\n            if isinstance(rv, (str, bytes, bytearray)) or isinstance(rv, cabc.Iterator):\n                # let the response class set the status and headers instead of\n                # waiting to do it manually, so that the class can handle any\n                # special logic\n                rv = self.response_class(\n                    rv,  # pyright: ignore\n                    status=status,\n                    headers=headers,  # type: ignore[arg-type]\n                )\n                status = headers = None\n            elif isinstance(rv, (dict, list)):","sourceCodeStart":1289,"sourceCodeEnd":1325,"githubUrl":"https://github.com/pallets/flask/blob/6a2f545bfd8ed31e19066a299296917e034aca58/src/flask/app.py#L1289-L1325","documentation":"Raised in `Flask.make_response()` (src/flask/app.py:1307) when the view's return value (after tuple unpacking) is None. A WSGI response needs a body, and the most common cause is a view that fell off the end without a `return` statement — Python implicitly returns None — so Flask names the offending endpoint to make the fix obvious.","triggerScenarios":"A view function with a missing `return` (e.g. only a code path for POST returns, GET falls through); `return None` explicitly; `return None, 200` or `(None, 200, headers)` — the None body is caught after tuple unpacking; a decorator or `before_request`-style wrapper that swallows the view's return value.","commonSituations":"Conditional branches where only one branch returns (`if form.validate(): return redirect(...)` with no else); views that call `render_template(...)` without returning it; custom decorators that forget `return f(*args, **kwargs)`; error handlers that log but return nothing; async views where a wrapper dropped the awaited result.","solutions":["Add a `return` for every code path in the view named in the error message — search it for branches that end without returning.","Check custom decorators wrapping the view: the wrapper must `return func(*args, **kwargs)`.","Make sure side-effect calls like `render_template()` or `redirect()` are returned, not just evaluated.","If a route legitimately has no body, `return ('', 204)` instead of nothing."],"exampleFix":"# before\n@app.route(\"/submit\", methods=[\"GET\", \"POST\"])\ndef submit():\n    if request.method == \"POST\":\n        return redirect(url_for(\"done\"))\n    render_template(\"form.html\")  # not returned!\n\n# after\n@app.route(\"/submit\", methods=[\"GET\", \"POST\"])\ndef submit():\n    if request.method == \"POST\":\n        return redirect(url_for(\"done\"))\n    return render_template(\"form.html\")","handlingStrategy":"validation","validationCode":"# lint/test guard: every code path must return\n# ruff/pylint flag inconsistent-return-statements (R1710)\ndef view():\n    if cond:\n        return render_template('a.html')\n    return render_template('b.html')  # no implicit None fall-through","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Ensure every branch of a view function returns a value; enable pylint R1710 / mypy strict returns","Return ('', 204) explicitly for intentionally empty responses instead of returning None","Cover every conditional branch of each view with a test-client test"],"tags":["flask","view-function","none-return","return-value"],"analyzedSha":"6a2f545bfd8ed31e19066a299296917e034aca58","analyzedAt":"2026-07-31T19:13:49.921Z","schemaVersion":2}