{"id":"d7d0b9069440b499","repo":"pallets/flask","slug":"view-function-mapping-is-overwriting-an-existing-e","errorCode":null,"errorMessage":"View function mapping is overwriting an existing endpoint function: {endpoint}","messagePattern":"View function mapping is overwriting an existing endpoint function: (.+?)","errorType":"exception","errorClass":"AssertionError","httpStatus":null,"severity":"error","filePath":"src/flask/sansio/app.py","lineNumber":657,"sourceCode":"                provide_automatic_options = (\n                    \"OPTIONS\" not in methods\n                    and self.config[\"PROVIDE_AUTOMATIC_OPTIONS\"]\n                )\n\n        if provide_automatic_options:\n            required_methods.add(\"OPTIONS\")\n\n        # Add the required methods now.\n        methods |= required_methods\n\n        rule_obj = self.url_rule_class(rule, methods=methods, **options)\n        rule_obj.provide_automatic_options = provide_automatic_options  # type: ignore[attr-defined]\n\n        self.url_map.add(rule_obj)\n        if view_func is not None:\n            old_func = self.view_functions.get(endpoint)\n            if old_func is not None and old_func != view_func:\n                raise AssertionError(\n                    \"View function mapping is overwriting an existing\"\n                    f\" endpoint function: {endpoint}\"\n                )\n            self.view_functions[endpoint] = view_func\n\n    @t.overload\n    def template_filter(self, name: T_template_filter) -> T_template_filter: ...\n    @t.overload\n    def template_filter(\n        self, name: str | None = None\n    ) -> t.Callable[[T_template_filter], T_template_filter]: ...\n    @setupmethod\n    def template_filter(\n        self, name: T_template_filter | str | None = None\n    ) -> T_template_filter | t.Callable[[T_template_filter], T_template_filter]:\n        \"\"\"Decorate a function to register it as a custom Jinja filter. The name\n        is optional. The decorator may be used without parentheses.\n","sourceCodeStart":639,"sourceCodeEnd":675,"githubUrl":"https://github.com/pallets/flask/blob/6a2f545bfd8ed31e19066a299296917e034aca58/src/flask/sansio/app.py#L639-L675","documentation":"An AssertionError from `Flask.add_url_rule` (src/flask/sansio/app.py:654-660). Flask maps each endpoint name to exactly one view function in `self.view_functions`; if the endpoint already has a function and the new `view_func` is a *different* object, registration would silently replace the old view, so Flask refuses. Registering the identical function object again for the same endpoint is allowed (the `old_func != view_func` check), which is why re-importing the same module is fine but a name collision is not.","triggerScenarios":"Two `@app.route` decorators on functions with the same name (endpoint defaults to `view_func.__name__`); explicitly passing the same `endpoint=` to two different views; decorating a view with a custom decorator that doesn't use `functools.wraps`, so every wrapped view is named 'wrapper' and the second registration collides; registering the same blueprint module's routes twice under one name; calling `add_url_rule` twice with different functions for one endpoint.","commonSituations":"Copy-pasting a route and forgetting to rename the function; custom auth/logging decorators missing `@functools.wraps(f)`; app modules imported twice via different paths (package vs script) creating distinct function objects; hot-reload or plugin code re-registering routes on a long-lived app.","solutions":["Add `@functools.wraps(f)` to any custom decorator applied between `@app.route` and the view function — this is the most common cause.","Rename the colliding view function or pass a unique `endpoint='...'` to one of the routes.","If the same handler should serve two URLs, stack multiple `@app.route` decorators on one function instead of defining two functions.","Check for double registration (module imported under two names, or setup code running twice) and register routes exactly once."],"exampleFix":"# before\ndef login_required(f):\n    def wrapper(*a, **kw):\n        return f(*a, **kw)\n    return wrapper  # every view becomes endpoint 'wrapper'\n\n# after\nimport functools\ndef login_required(f):\n    @functools.wraps(f)\n    def wrapper(*a, **kw):\n        return f(*a, **kw)\n    return wrapper","handlingStrategy":"validation","validationCode":"if 'my_endpoint' in app.view_functions:\n    raise RuntimeError('endpoint already registered')\napp.add_url_rule('/x', 'my_endpoint', view)","typeGuard":"def endpoint_free(app, endpoint):\n    return endpoint not in app.view_functions","tryCatchPattern":"try:\n    app.add_url_rule(rule, endpoint, view)\nexcept AssertionError:\n    log.error('Endpoint %s collides; pick a unique endpoint name', endpoint)","preventionTips":["Give every view function a unique name, or pass an explicit unique endpoint= argument","Beware decorators that don't use functools.wraps — wrapped views all become named 'wrapper'","When registering routes in loops, derive the endpoint from the loop variable, not the function name"],"tags":["flask","python","routing","endpoint","decorators"],"analyzedSha":"6a2f545bfd8ed31e19066a299296917e034aca58","analyzedAt":"2026-07-31T19:13:49.921Z","schemaVersion":2}