{"record":{"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/3596b1ab61cea85edb8970e83ff61daa073facf8/src/flask/sansio/blueprints.py#L197-L233","documentation":"Like the app guard, a Blueprint sets _got_registered_once=True once it has been registered on any app. Blueprint setup methods (@setupmethod on the blueprint: route, add_url_rule, before_request, errorhandler, etc.) call _check_setup_finished and raise AssertionError if called after the first registration, because deferred functions are replayed only at registration time.","triggerScenarios":"Registering the blueprint with app.register_blueprint(bp) and then calling bp.route(...)/bp.add_url_rule(...)/bp.errorhandler(...)/bp.before_app_request(...) afterwards; defining routes in a module imported lazily after registration.","commonSituations":"Plugin packages that register a blueprint then extend it; circular imports causing blueprint mutation after registration; tests that reuse one blueprint instance across multiple test app registrations and try to add routes between.","solutions":["Define all routes/handlers on the blueprint BEFORE calling app.register_blueprint(bp).","Use a fresh blueprint instance per registration if you must mutate it (factory function returning a new Blueprint).","For shared extension behavior, register additional blueprints rather than mutating an already-registered one."],"exampleFix":"// before\napp.register_blueprint(bp)\n@bp.route('/late')  # raises\ndef late(): ...\n\n// after\n@bp.route('/late')\ndef late(): ...\napp.register_blueprint(bp)","handlingStrategy":"validation","validationCode":"def assert_bp_settable(bp):\n    if getattr(bp, '_got_registered_once', False):\n        raise RuntimeError(f'blueprint {bp.name!r} already registered; configure before register_blueprint')\n","typeGuard":"def is_bp_setup_open(bp) -> bool:\n    return not getattr(bp, '_got_registered_once', False)\n","tryCatchPattern":"try:\n    bp.add_url_rule('/x', view_func=fn)\nexcept AssertionError as e:\n    if 'blueprint' in str(e) and 'no longer be called' in str(e):\n        # use a fresh blueprint instance and retry\n        raise","preventionTips":["Define all blueprint routes/handlers before register_blueprint.","Use a blueprint factory to get a fresh instance if you must rebuild.","Do not extend a blueprint from another module after it has been mounted."],"tags":["flask","blueprint","lifecycle","assertion","configuration"],"backgroundTag":null,"analyzedSha":"3596b1ab61cea85edb8970e83ff61daa073facf8","analyzedAt":"2026-08-11T20:11:52.622Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}