pallets/flask · error · AssertionError

View function mapping is overwriting an existing endpoint fu

Error message

View function mapping is overwriting an existing endpoint function: {endpoint}

What it means

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.

Source

Thrown at src/flask/sansio/app.py:657

                provide_automatic_options = (
                    "OPTIONS" not in methods
                    and self.config["PROVIDE_AUTOMATIC_OPTIONS"]
                )

        if provide_automatic_options:
            required_methods.add("OPTIONS")

        # Add the required methods now.
        methods |= required_methods

        rule_obj = self.url_rule_class(rule, methods=methods, **options)
        rule_obj.provide_automatic_options = provide_automatic_options  # type: ignore[attr-defined]

        self.url_map.add(rule_obj)
        if view_func is not None:
            old_func = self.view_functions.get(endpoint)
            if old_func is not None and old_func != view_func:
                raise AssertionError(
                    "View function mapping is overwriting an existing"
                    f" endpoint function: {endpoint}"
                )
            self.view_functions[endpoint] = view_func

    @t.overload
    def template_filter(self, name: T_template_filter) -> T_template_filter: ...
    @t.overload
    def template_filter(
        self, name: str | None = None
    ) -> t.Callable[[T_template_filter], T_template_filter]: ...
    @setupmethod
    def template_filter(
        self, name: T_template_filter | str | None = None
    ) -> T_template_filter | t.Callable[[T_template_filter], T_template_filter]:
        """Decorate a function to register it as a custom Jinja filter. The name
        is optional. The decorator may be used without parentheses.

View on GitHub ↗ (pinned to 6a2f545bfd)

Solutions

  1. Add `@functools.wraps(f)` to any custom decorator applied between `@app.route` and the view function — this is the most common cause.
  2. Rename the colliding view function or pass a unique `endpoint='...'` to one of the routes.
  3. If the same handler should serve two URLs, stack multiple `@app.route` decorators on one function instead of defining two functions.
  4. Check for double registration (module imported under two names, or setup code running twice) and register routes exactly once.

Example fix

# before
def login_required(f):
    def wrapper(*a, **kw):
        return f(*a, **kw)
    return wrapper  # every view becomes endpoint 'wrapper'

# after
import functools
def login_required(f):
    @functools.wraps(f)
    def wrapper(*a, **kw):
        return f(*a, **kw)
    return wrapper
Defensive patterns

Strategy: validation

Validate before calling

if 'my_endpoint' in app.view_functions:
    raise RuntimeError('endpoint already registered')
app.add_url_rule('/x', 'my_endpoint', view)

Type guard

def endpoint_free(app, endpoint):
    return endpoint not in app.view_functions

Try / catch

try:
    app.add_url_rule(rule, endpoint, view)
except AssertionError:
    log.error('Endpoint %s collides; pick a unique endpoint name', endpoint)

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


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