pallets/flask · error · TypeError

Use the 'route' decorator to use the 'methods' argument.

Error message

Use the 'route' decorator to use the 'methods' argument.

What it means

The HTTP-method shortcut decorators (get, post, put, delete, patch) route through _method_route, which hardcodes methods=[method]. Passing methods in options would be ambiguous/contradictory, so Flask raises TypeError and points the user to the generic route() decorator instead.

Solutions

  1. Use @app.route('/x', methods=[...]) when you need to control methods.
  2. Remove the methods kwarg from the method shortcut call (the shortcut already implies the method).
  3. If merging options programmatically, pop 'methods' before passing to the shortcut.

Example fix

// before
@app.get('/items', methods=['GET', 'HEAD'])
def items(): ...

// after
@app.route('/items', methods=['GET', 'HEAD'])
def items(): ...
Defensive patterns

Strategy: type-guard

Validate before calling

def call_method_shortcut(decorator, rule, **options):
    options.pop('methods', None)  # explicit guard
    return decorator(rule, **options)

Type guard

def options_has_no_methods(options: dict) -> bool:
    return 'methods' not in options

Prevention

When it happens

Trigger: Calling @app.get('/x', methods=['POST']); @app.post('/x', methods=['GET','POST']); passing methods= to any of get/post/put/delete/patch via kwargs.

Common situations: Copy-pasting options from an @app.route call onto a method shortcut; wanting to add HEAD/OPTIONS to a method shortcut; config-driven decorators merging options dicts that include methods.

Related errors


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

Appendix: source

Thrown at src/flask/sansio/scaffold.py:291

        """The Jinja loader for this object's templates. By default this
        is a class :class:`jinja2.loaders.FileSystemLoader` to
        :attr:`template_folder` if it is set.

        .. versionadded:: 0.5
        """
        if self.template_folder is not None:
            return FileSystemLoader(os.path.join(self.root_path, self.template_folder))
        else:
            return None

    def _method_route(
        self,
        method: str,
        rule: str,
        options: dict[str, t.Any],
    ) -> t.Callable[[T_route], T_route]:
        if "methods" in options:
            raise TypeError("Use the 'route' decorator to use the 'methods' argument.")

        return self.route(rule, methods=[method], **options)

    @setupmethod
    def get(self, rule: str, **options: t.Any) -> t.Callable[[T_route], T_route]:
        """Shortcut for :meth:`route` with ``methods=["GET"]``.

        .. versionadded:: 2.0
        """
        return self._method_route("GET", rule, options)

    @setupmethod
    def post(self, rule: str, **options: t.Any) -> t.Callable[[T_route], T_route]:
        """Shortcut for :meth:`route` with ``methods=["POST"]``.

        .. versionadded:: 2.0
        """
        return self._method_route("POST", rule, options)

View on GitHub (pinned to 3596b1ab61)