{"record":{"id":"50e2f4bc8a628739","repo":"pallets/flask","slug":"allowed-methods-must-be-a-list-of-strings-for-exa","errorCode":null,"errorMessage":"Allowed methods must be a list of strings, for example: @app.route(..., methods=[\"POST\"])","messagePattern":"Allowed methods must be a list of strings, for example: @app\\.route\\(\\.\\.\\., methods=\\[\"POST\"\\]\\)","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"src/flask/sansio/app.py","lineNumber":624,"sourceCode":"        self,\n        rule: str,\n        endpoint: str | None = None,\n        view_func: ft.RouteCallable | None = None,\n        provide_automatic_options: bool | None = None,\n        **options: t.Any,\n    ) -> None:\n        if endpoint is None:\n            endpoint = _endpoint_from_view_func(view_func)  # type: ignore\n        options[\"endpoint\"] = endpoint\n        methods = options.pop(\"methods\", None)\n\n        # if the methods are not given and the view_func object knows its\n        # methods we can use that instead.  If neither exists, we go with\n        # a tuple of only ``GET`` as default.\n        if methods is None:\n            methods = getattr(view_func, \"methods\", None) or (\"GET\",)\n        if isinstance(methods, str):\n            raise TypeError(\n                \"Allowed methods must be a list of strings, for\"\n                ' example: @app.route(..., methods=[\"POST\"])'\n            )\n        methods = {item.upper() for item in methods}\n\n        # Methods that should always be added\n        required_methods: set[str] = set(getattr(view_func, \"required_methods\", ()))\n\n        if provide_automatic_options is None:\n            provide_automatic_options = getattr(\n                view_func, \"provide_automatic_options\", None\n            )\n\n            if provide_automatic_options is None:\n                provide_automatic_options = (\n                    \"OPTIONS\" not in methods\n                    and self.config[\"PROVIDE_AUTOMATIC_OPTIONS\"]\n                )","sourceCodeStart":606,"sourceCodeEnd":642,"githubUrl":"https://github.com/pallets/flask/blob/3596b1ab61cea85edb8970e83ff61daa073facf8/src/flask/sansio/app.py#L606-L642","documentation":"In add_url_rule, Flask expects the methods argument to be an iterable of strings. If methods is a single str (e.g. \"GET\"), Python would otherwise silently iterate character-by-character, so Flask explicitly raises TypeError with a corrective hint. This prevents silently registering methods like 'G','E','T'.","triggerScenarios":"Passing methods=\"POST\" or methods=\"GET\" (a bare string) to app.add_url_rule or @app.route(..., methods=...); passing a methods string to app.url_rule_class indirectly.","commonSituations":"Developer forgets the list brackets; copying a single-method example and dropping the brackets; dataclass/config-driven route registration that yields a string for single-method routes.","solutions":["Wrap the value in a list: methods=[\"POST\"] instead of methods=\"POST\".","For a single method shortcut, use @app.get(rule) / @app.post(rule) which do not take methods.","If generating methods dynamically, coerce to a list: methods=[m] if isinstance(m, str) else m."],"exampleFix":"// before\n@app.route('/login', methods=\"POST\")\ndef login(): ...\n\n// after\n@app.route('/login', methods=[\"POST\"])\ndef login(): ...","handlingStrategy":"type-guard","validationCode":"def normalize_methods(methods):\n    if isinstance(methods, str):\n        return [methods]\n    return list(methods)\n","typeGuard":"def is_methods_arg_valid(methods) -> bool:\n    return not isinstance(methods, str)\n","tryCatchPattern":null,"preventionTips":["Always pass methods as a list, even for a single method.","Prefer @app.get/@app.post shortcuts for single-method routes.","Lint route registrations to flag methods=<str>."],"tags":["flask","routing","type-error","methods","configuration"],"backgroundTag":null,"analyzedSha":"3596b1ab61cea85edb8970e83ff61daa073facf8","analyzedAt":"2026-08-11T20:11:52.622Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}