pallets/flask · error · AssertionError

The setup method '{f_name}' can no longer be called on the a

Error message

The setup method '{f_name}' can no longer be called on the application. It has already handled its first request, any changes will not be applied consistently.
Make sure all imports, decorators, functions, etc. needed to set up the application are done before running it.

What it means

An AssertionError from `Flask._check_setup_finished` (src/flask/sansio/app.py:410-419), which every `@setupmethod`-decorated API calls first. Once the app has served its first request (`_got_first_request` is True), Flask freezes setup: routes, error handlers, before/after-request hooks, and similar registrations would only partially apply (e.g. a route added after some workers already built their URL map), so Flask fails loudly instead of applying changes inconsistently. Added as a hard error in Flask 2.3.

Source

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

        #:        def to_python(self, value):
        #:            return value.split(',')
        #:        def to_url(self, values):
        #:            return ','.join(super(ListConverter, self).to_url(value)
        #:                            for value in values)
        #:
        #:    app = Flask(__name__)
        #:    app.url_map.converters['list'] = ListConverter
        self.url_map = self.url_map_class(host_matching=host_matching)

        self.subdomain_matching = subdomain_matching

        # tracks internally if the application already handled at least one
        # request.
        self._got_first_request = False

    def _check_setup_finished(self, f_name: str) -> None:
        if self._got_first_request:
            raise AssertionError(
                f"The setup method '{f_name}' can no longer be called"
                " on the application. It has already handled its first"
                " request, any changes will not be applied"
                " consistently.\n"
                "Make sure all imports, decorators, functions, etc."
                " needed to set up the application are done before"
                " running it."
            )

    @cached_property
    def name(self) -> str:
        """The name of the application.  This is usually the import name
        with the difference that it's guessed from the run file if the
        import name is main.  This name is used as a display name when
        Flask needs the name of the application.  It can be set and overridden
        to change the value.

        .. versionadded:: 0.8

View on GitHub ↗ (pinned to 6a2f545bfd)

Solutions

  1. Move all route/handler registration to import time or inside your `create_app()` factory, before the app is served.
  2. In tests, create a fresh app per test (pytest fixture calling the factory) instead of mutating one shared instance after requests ran.
  3. If you genuinely need per-request dynamic dispatch, register one catch-all route up front and dispatch inside it rather than adding rules at runtime.

Example fix

# before
@app.route("/")
def index():
    @app.route("/late")  # raises after first request
    def late():
        return "hi"
    return "ok"

# after
@app.route("/")
def index():
    return "ok"

@app.route("/late")
def late():
    return "hi"
Defensive patterns

Strategy: validation

Validate before calling

if not app._got_first_request:
    app.before_request(my_hook)
else:
    raise RuntimeError('Too late to register setup hooks')

Type guard

def can_still_setup(app):
    return not getattr(app, '_got_first_request', False)

Try / catch

try:
    app.before_request(hook)
except AssertionError:
    log.error('Setup method called after first request; move registration to app factory')

Prevention

When it happens

Trigger: Calling any setup method — `@app.route`, `add_url_rule`, `before_request`, `errorhandler`, `register_blueprint`, `teardown_request`, etc. — after the app has handled at least one request. Typical shapes: registering a route inside a view function or `before_request` callback, lazily importing a module that decorates routes only when a request first touches it, or a test that calls `app.test_client().get(...)` and then adds more routes to the same app instance.

Common situations: Lazy/conditional imports of view modules inside request handlers; app factories that return a shared module-level app which tests mutate after exercising it; plugin systems that register endpoints on demand; upgrading from Flask <2.3 where `before_first_request` existed and some of these patterns went unnoticed.

Related errors


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