{"id":"3aee6862ff7e028c","repo":"pallets/flask","slug":"the-setup-method-f-name-can-no-longer-be-calle-3aee68","errorCode":null,"errorMessage":"The setup method '{f_name}' can no longer be called on the blueprint '{self.name}'. It has already been registered at least once, any changes will not be applied consistently.\nMake sure all imports, decorators, functions, etc. needed to set up the blueprint are done before registering it.","messagePattern":"The setup method '(.+?)' can no longer be called on the blueprint '(.+?)'\\. It has already been registered at least once, any changes will not be applied consistently\\.\nMake sure all imports, decorators, functions, etc\\. needed to set up the blueprint are done before registering it\\.","errorType":"exception","errorClass":"AssertionError","httpStatus":null,"severity":"error","filePath":"src/flask/sansio/blueprints.py","lineNumber":215,"sourceCode":"\n        if \".\" in name:\n            raise ValueError(\"'name' may not contain a dot '.' character.\")\n\n        self.name = name\n        self.url_prefix = url_prefix\n        self.subdomain = subdomain\n        self.deferred_functions: list[DeferredSetupFunction] = []\n\n        if url_defaults is None:\n            url_defaults = {}\n\n        self.url_values_defaults = url_defaults\n        self.cli_group = cli_group\n        self._blueprints: list[tuple[Blueprint, dict[str, t.Any]]] = []\n\n    def _check_setup_finished(self, f_name: str) -> None:\n        if self._got_registered_once:\n            raise AssertionError(\n                f\"The setup method '{f_name}' can no longer be called on the blueprint\"\n                f\" '{self.name}'. It has already been registered at least once, any\"\n                \" changes will not be applied consistently.\\n\"\n                \"Make sure all imports, decorators, functions, etc. needed to set up\"\n                \" the blueprint are done before registering it.\"\n            )\n\n    @setupmethod\n    def record(self, func: DeferredSetupFunction) -> None:\n        \"\"\"Registers a function that is called when the blueprint is\n        registered on the application.  This function is called with the\n        state as argument as returned by the :meth:`make_setup_state`\n        method.\n        \"\"\"\n        self.deferred_functions.append(func)\n\n    @setupmethod\n    def record_once(self, func: DeferredSetupFunction) -> None:","sourceCodeStart":197,"sourceCodeEnd":233,"githubUrl":"https://github.com/pallets/flask/blob/6a2f545bfd8ed31e19066a299296917e034aca58/src/flask/sansio/blueprints.py#L197-L233","documentation":"An AssertionError from `Blueprint._check_setup_finished` (src/flask/sansio/blueprints.py:213-221), the blueprint counterpart of the app-level setup freeze. Every `@setupmethod` on a blueprint (route, before_request, errorhandler, record, register_blueprint, ...) checks `_got_registered_once`; once the blueprint has been registered on an application, its deferred setup functions have already been replayed onto that app, so later additions would exist on some registrations and not others. Flask 2.3 made this a hard error.","triggerScenarios":"Calling `@bp.route`, `bp.before_request`, `bp.errorhandler`, etc. after `app.register_blueprint(bp)` has run for that blueprint object. Classic shapes: registering the blueprint at the top of a module and defining routes below it; a factory that registers a shared module-level blueprint, then a test or second factory call tries to add more routes; conditionally importing a routes module only after registration.","commonSituations":"Import-order mistakes where `create_app()` registers the blueprint before the module defining its routes is fully imported; tests mutating a module-level blueprint that a previous test's app already registered; plugin architectures adding routes to an already-mounted blueprint; Flask <2.3 code that silently tolerated this now failing after upgrade.","solutions":["Move `app.register_blueprint(bp)` after all of the blueprint's routes and handlers are defined — typically registration lives in `create_app()`, which imports the fully-built blueprint module.","In tests, build a fresh app (and fresh blueprints if they're created dynamically) per test rather than re-decorating shared module-level blueprints.","If routes are added conditionally, decide them before registration (feature flags evaluated in the blueprint module), not afterward."],"exampleFix":"# before\nbp = Blueprint(\"admin\", __name__)\napp.register_blueprint(bp)\n\n@bp.route(\"/users\")  # AssertionError: already registered\ndef users(): ...\n\n# after\nbp = Blueprint(\"admin\", __name__)\n\n@bp.route(\"/users\")\ndef users(): ...\n\napp.register_blueprint(bp)","handlingStrategy":"validation","validationCode":"if bp._got_registered_once:\n    raise RuntimeError('Blueprint already registered; define routes before app.register_blueprint')\nbp.route('/x')(view)","typeGuard":"def can_modify_blueprint(bp):\n    return not getattr(bp, '_got_registered_once', False)","tryCatchPattern":"try:\n    bp.before_request(hook)\nexcept AssertionError:\n    log.error('Blueprint %s already registered; move setup before register_blueprint', bp.name)","preventionTips":["Define all blueprint routes/hooks at module level, then register the blueprint last in the app factory","Never add routes to a blueprint after app.register_blueprint has been called on it","Avoid conditional/lazy route registration inside request handling"],"tags":["flask","python","blueprints","lifecycle","setup"],"analyzedSha":"6a2f545bfd8ed31e19066a299296917e034aca58","analyzedAt":"2026-07-31T19:13:49.921Z","schemaVersion":2}