"Request method 'GET' is not supported" is Spring's way of saying HTTP 405 Method Not Allowed: the URL matched a route, but that route only accepts POST (or PUT, PATCH, DELETE), and the request arrived as GET. The plain servlet variant, "HTTP method GET is not supported by this URL", means the same thing coming out of HttpServlet when nobody overrode doGet. Neither is a routing miss (that would be a 404), and neither is a crash. In almost every case the fix is one of two things: make the caller send the right verb, or add a GET handler because the URL is supposed to serve something on GET.
This is the GET counterpart of our older guide on fixing "Request method 'POST' not supported". I wrote it because that post kept ranking for GET queries it did not really answer.
Quick summary
- The error is an HTTP 405, not a 404 or 500. The route exists; the verb does not match. Spring throws
HttpRequestMethodNotSupportedException,HttpServletanswers from its defaultdoGet. - Spring's response carries an
Allowheader (for exampleAllow: POST). Read it first: it tells you which side to fix. - 8 causes cover nearly every report: browser address bar on a POST-only URL, a form defaulting to GET, a missing
@GetMapping, a 302 redirect after POST, a login redirect replaying a POST URL, a servlet withoutdoGet, framework method lists in Django, Flask or Express, and an API client using the wrong verb. - Express behaves differently: an unmatched GET returns 404 "Cannot GET /path", not 405, unless you add a fallback handler.
- A 405 on a webhook or form-processing endpoint is correct behavior. Point uptime checks at a GET health endpoint rather than "fixing" the route.
What the error means
Every HTTP request has a method (GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS). A server maps URL plus method to a handler. When the URL matches but no handler is registered for that method, the correct answer is 405 Method Not Allowed with an Allow header naming the methods that would have worked. The HTTP status code reference lists the rest of the 4xx codes, and explains why 405 differs from 501.
The exact wording depends on the stack:
| Where you see it | Text | Status |
|---|---|---|
| Spring MVC / Spring Boot log | Resolved [org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'GET' is not supported] (Spring 5.x logs "Request method 'GET' not supported") |
405 |
| Spring Boot JSON body | {"timestamp":"...","status":405,"error":"Method Not Allowed","path":"/api/orders"} |
405 |
| Java servlet (Tomcat, Jetty) | HTTP method GET is not supported by this URL from HttpServlet.doGet |
405 (400 on HTTP/1.0) |
| Flask / Werkzeug | Method Not Allowed. The method is not allowed for the requested URL. |
405 |
| Django | Log line Method Not Allowed (GET): /orders/, empty body |
405 |
| Express | Cannot GET /orders |
404 by default |
What causes "Request method 'GET' is not supported"?
Eight situations account for almost every occurrence I have debugged or seen reported.
- Someone opened a POST-only URL in the browser address bar, clicked a bookmark to it, or a crawler fetched it. The address bar can only send GET.
- An HTML form points at a
@PostMappingroute but hasmethod="get", or nomethodattribute at all. The default form method is GET. - The controller has
@PostMapping("/orders")and nothing for GET, but a template links to/ordersexpecting a list page. Missing@GetMapping, or a@GetMappingon a slightly different path (/orders/vs/orders, a typo in a path variable). - A POST handler returns
redirect:/ordersand/ordersis POST-only. A 302 or 303 redirect makes the browser follow with GET. - Spring Security intercepted a POST because the session had expired, sent the user to the login page, then replayed the saved URL as a GET after login. The saved-request handler always redirects with GET.
- A servlet overrides
doPostand nothing else, soHttpServlet's defaultdoGetanswers with the "not supported by this URL" message. - A Flask route declared
methods=['POST'], a Django view wrapped in@require_POSTor a class-based view with onlypost(), an Expressapp.postwith noapp.get. The framework is doing what it was told. - An API client, script, Postman collection or monitor calls the endpoint with GET when the docs say POST, or the reverse. Some RPC-style APIs describe this as "method not found" because they treat the operation name and the verb together, so check both.
How to read the stack trace
The Spring log line looks like this:
WARN 8123 --- [nio-8080-exec-3] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'GET' is not supported]There is no controller class in that line, which is why people get stuck. Spring resolved the exception before any handler method ran, so the useful information is elsewhere: the request path (log it, or read it from the JSON body's path field) and the Allow header on the response. Reproduce with curl to see both:
curl -i http://localhost:8080/api/orders
HTTP/1.1 405
Allow: POST
Content-Type: application/json
{"timestamp":"2026-08-15T09:12:44.118+00:00","status":405,"error":"Method Not Allowed","path":"/api/orders"}Allow: POST says the route is registered for POST only. Now search the codebase for that path inside @PostMapping, @RequestMapping or @PutMapping and you have the handler. If the Allow header lists a method you did not expect, you may be hitting a different route than you thought, for example a catch-all pattern like /api/**.
For a servlet, Tomcat's error page reads "HTTP Status 405, Method Not Allowed" (Tomcat prints a dash between the two) and the message is the HttpServlet string. Open the servlet mapped to that URL in web.xml or @WebServlet and look at which doX methods it declares.
How to fix it step by step
1. Read the status code and the Allow header
Run curl -i (or open the Network tab in DevTools) and confirm you are looking at a 405, not a 404 or a 403. A 404 means no route matched at all; a 403 after a form submit is usually CSRF, and the fix is different. The Allow header decides the rest of the process.
2. Find the handler that matched
In Spring, grep for the path in mapping annotations. In a servlet app, open the servlet class. In Flask, Django or Express, open the route or view definition. You are looking for the method list attached to that path.
3. Decide who is wrong: the client or the route
If the endpoint processes a form, receives a webhook or mutates data, GET is supposed to fail. Fix the caller: the form method, the fetch call, the redirect target, the monitor. If the URL is meant to show a page or return a resource and nobody wrote that handler, the route is what needs to change.
4. Add or widen the handler
Spring Boot, the usual layout with a GET that renders and a POST that processes:
@Controller
@RequestMapping("/orders")
public class OrderController {
@GetMapping
public String list(Model model) {
model.addAttribute("orders", service.findAll());
return "orders/list";
}
@PostMapping
public String create(@ModelAttribute OrderForm form) {
service.create(form);
return "redirect:/orders";
}
}If one method must serve both verbs (rare, but some legacy callback URLs need it):
@RequestMapping(value = "/callback", method = {RequestMethod.GET, RequestMethod.POST})
public ResponseEntity<Void> callback(HttpServletRequest request) {
...
}Plain servlet, override doGet instead of relying on the base class:
@WebServlet("/orders")
public class OrderServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
req.getRequestDispatcher("/WEB-INF/orders.jsp").forward(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
// process the submission
resp.sendRedirect(req.getContextPath() + "/orders");
}
}Express, where the default is a 404 and you may want an explicit 405 with Allow:
app.route('/orders')
.get((req, res) => res.render('orders'))
.post(createOrder)
.all((req, res) => res.set('Allow', 'GET, POST').sendStatus(405));Flask:
@app.route('/orders', methods=['GET', 'POST'])
def orders():
if request.method == 'POST':
return create_order()
return render_template('orders.html')Django, function view and class-based view:
from django.views.decorators.http import require_http_methods
@require_http_methods(["GET", "POST"])
def orders(request):
...
class OrderView(View):
def get(self, request):
...
def post(self, request):
...5. Check redirects and login flows
After a successful POST, redirect to a URL that answers GET. redirect:/orders is fine once /orders has a @GetMapping; redirect:/orders/create is not if create is POST-only.
If you see the 405 right after logging in, the saved request is being replayed: either give that URL a GET handler that shows the form again, or configure the login success handler with a fixed target (defaultSuccessUrl("/dashboard", true) in Spring Security). CSRF failures return 403, so a 405 in this flow is the redirect, not the token.
6. Verify and monitor
Run the curl command again for both verbs and confirm GET returns 200 (or the intended 405 with Allow) and POST still works. Then add an uptime check against a GET-able health endpoint so a future regression on that route shows up before a user reports it.
When is 405 the correct behavior?
More often than the bug reports suggest. Webhook receivers, form processors, "mark as read" endpoints and anything that mutates state should reject GET, because GET requests get prefetched, cached, bookmarked and crawled. Adding a GET handler that does the POST's work would turn every crawler visit into a write.
For those routes, the right fix is on the client side and the response side: return 405 with an Allow header, do not return 200 with an error message in the body, and do not point an availability check at the POST route with a GET. If a monitor needs to cover the endpoint, give the service a small GET health route and check that instead. Our guide to the most common HTTP status codes covers the 4xx and 5xx codes you are likely to see next to a 405 in the same logs.
Framework cheat sheet
| Framework | Restrict a route to POST | Allow GET too | Response when GET is not allowed |
|---|---|---|---|
| Spring MVC | @PostMapping("/x") |
add @GetMapping("/x") or method = {GET, POST} |
405, Allow header, HttpRequestMethodNotSupportedException |
| Java servlet | override doPost only |
override doGet |
405 "HTTP method GET is not supported by this URL" |
| Express | app.post('/x', h) |
app.get('/x', h2) |
404 "Cannot GET /x" unless you add .all() |
| Flask | methods=['POST'] |
methods=['GET', 'POST'] |
405 Werkzeug page |
| Django | @require_POST or CBV with post() only |
@require_http_methods(["GET","POST"]) or add get() |
405, HttpResponseNotAllowed |
If the message you are chasing says POST instead of GET, the causes mirror these and the POST version of this guide walks through them.
FAQ
What does "Request method 'GET' is not supported" mean? ▼
It is the Spring MVC wording for an HTTP 405 Method Not Allowed. The URL exists and matched a handler, but that handler is mapped to POST, PUT or another verb, and the request came in as GET. Spring throws HttpRequestMethodNotSupportedException and returns 405 with an Allow header listing the verbs the route does accept.
Why do I get "HTTP method GET is not supported by this URL" in a Java servlet? ▼
That message comes from the default doGet implementation in HttpServlet. If your servlet only overrides doPost, any GET request falls through to the base class, which answers 405 (or 400 on HTTP/1.0 clients). Override doGet in your servlet, or handle both verbs in service(), and the message goes away.
How do I allow both GET and POST on the same Spring endpoint? ▼
Use @RequestMapping(value = "/path", method = {RequestMethod.GET, RequestMethod.POST}) on one method, or keep two methods, one with @GetMapping and one with @PostMapping, on the same path. The second option is cleaner because the GET handler usually renders a form or a resource while the POST handler processes a submission.
Why does my POST work but the page shows 405 after a redirect? ▼
A 302 or 303 redirect makes the browser follow with GET. If the redirect target is a POST-only URL, the follow-up GET hits 405. Redirect to a page that answers GET, or use 307/308 if you really need the method preserved. Spring Security's saved-request replay after login is a common trigger for this.
Is a 405 on a POST-only endpoint a bug? ▼
Not when someone opens the endpoint in a browser or a crawler hits it with GET. Webhook receivers, form processors and mutation endpoints are supposed to reject GET. Keep the 405, make sure the Allow header is present, and point uptime checks at a GET-able health endpoint instead of the POST route.




