pallets/flask · error · AssertionError

The setup method ' ' can no longer be called on the…

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

Flask marks an application with _got_first_request=True once it has handled its first request. Any method decorated with @setupmethod (route, errorhandler, before_request, context_processor, etc.) calls _check_setup_finished, which raises this AssertionError if invoked afterwards, because applying changes mid-flight would leave the app in an inconsistent state. It is a hard guard, not a warning.

Solutions

  1. Move all @app.route/@app.errorhandler/@app.before_request registrations and register_blueprint calls to module import time, before app.run() or before the test client issues its first request.
  2. If registration must be dynamic, gate it behind a flag set during startup, or use application factories that fully configure the app before it is returned/served.
  3. In tests, build a fresh app per test (app factory pattern) so _got_first_request resets; do configuration before the first client request.
  4. Search for any code path that mutates the app from inside a view, before/after handler, or background thread and hoist it out.

Example fix

// before
@app.route('/first')
def first(): return 'hi'

@app.after_request  # called after first request in a test
def add_header(resp): return resp

// after - register all setup at import time, before any request
@app.route('/first')
def first(): return 'hi'

@app.after_request
def add_header(resp): return resp
# ensure app.run()/client calls happen only after all setup is imported
Defensive patterns

Strategy: validation

Validate before calling

def assert_app_settable(app):
    if getattr(app, '_got_first_request', False):
        raise RuntimeError('app already served first request; register routes earlier')

Type guard

def is_app_setup_open(app) -> bool:
    return not getattr(app, '_got_first_request', False)

Try / catch

try:
    app.add_url_rule('/x', view_func=handler)
except AssertionError as e:
    if 'setup method' in str(e):
        # move registration to startup; do not swallow silently
        raise

Prevention

When it happens

Trigger: Calling app.route/errorhandler/before_request/teardown_request/register_blueprint/template_filter/etc. after app.run() has started serving, after a request has been dispatched (e.g. inside a view or a test that already did client.get(...)), or lazily registering routes on first import inside a request handler.

Common situations: Importing route modules lazily inside a view instead of at startup; registering blueprints triggered by the first request; running setup code in a background thread after the server started; in tests calling app.route decorators after the first client request.

Related errors


AI-assisted analysis of pallets/flask@3596b1ab61 (2026-08-11). Data as JSON: /api/errors/beaa8a8e3a75ed57. Report an issue: GitHub.

Appendix: 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 3596b1ab61)