okhttp: java.lang.IllegalArgumentException: method GET must not have a request body.

What kind of issue is this?

  • Question. This issue tracker is not the place for questions. If you want to ask how to do something, or to understand why something isn’t working the way you expect it to, use Stack Overflow. https://stackoverflow.com/questions/tagged/okhttp

  • Bug report. If you’ve found a bug, spend the time to write a failing test. Bugs with tests get fixed. Here’s an example: https://gist.github.com/swankjesse/981fcae102f513eb13ed

  • Feature Request. Start by telling us what problem you’re trying to solve. Often a solution already exists! Don’t send pull requests to implement new features without first getting our support. Sometimes we leave features out on purpose to keep the project small.

I’m trying to do a get request to Elasticsearch with a query body but OkHttp doesn’t allow that. The query works with curl:

curl -XGET 'localhost:9200/fncd/event/_search?scroll=1m' -d '
{
    "query": {
	    "range" : {
	        "lastUpdated" : {
	            "gte": 1486184400000
	        }
	    }
    }
}
'

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Reactions: 17
  • Comments: 21 (6 by maintainers)

Most upvoted comments

It’s unlikely we’ll ever support request bodies with GET.

No further action to take on this.

OkHttp is an opinionated HTTP client. By constraining what we support to what the specs allow, we’re able to keep things relatively simple and offer great features like smart caching.

Elasticsearch is wrong for exposing APIs that use GET requests with bodies. They should fix their API.

can use @HTTP(method = "get", path = "/user/get", hasBody = true), Use lowercase get to bypass restrictions!

please

I may have misunderstood you before as you’re not bringing up OkHttp specific concerns, but concerns about the surrounding ecosystem.

I respect the attitude towards the de facto state of things that GET requests may be somewhat surprising. If you want to take the position that it should be OkHttp’s problem to solve the general (but incorrect) expectation that GETs don’t have bodies, sure. Probably the best point of view from a stability perspective.

To me personally though, it’s somewhat surprising that OkHttp goes to the length it currently does. Actively breaking GET requests with bodies in OkHttp feels out of place to me when all relevant specs allow it, real world use cases exist, and as far as I know this behavior is not shared by other common HTTP clients. It effectively makes OkHttp a “subset-of-HTTP client”, effectively also making it opinionated towards how servers should behave. Again - I respect you guys are making different choices than other people - but the limitation seems unexpected and artificial to me.

Yep, that’s an accurate description of the project. We don’t do the long tail of all features of every spec, but enough that makes the common stuff safe & easy. We also try hard to keep the project small and minimize dependencies.

Off the top of my head there’s a few other places where our opinions show up:

  • We lock down TLS beyond what the base platform permits.
  • We don’t support HTTP/2 over plaintext.
  • The only way to customize caching is via HTTP cache headers.

Looking at this list, it’s a lot of opinions that are shared by browsers. Which makes me wonder – can Chrome or Firefox do HTTP GETs with request bodies? That’d be something that might convince me we’re too far from the common path.

A payload within a GET request message has no defined semantics; sending a payload body on a GET request might cause some existing implementations to reject the request.

OkHttp is one of those existing implementations!

Permitting GETS to carry a semantic-free request body comes at a significant cost.

  • Caching will behave unpredictably
  • Interceptors may crash or leak resources
  • Request bodies may interfere with pooled HTTP/1 connections, permitting request smuggling attacks.

Could you explain your use case? I’ve never heard a compelling use case other than “elastic thought it would be cool LOL”.

If you wanna make get request with body, through OkHttp / Retrofit, use this working solution, from @chentianming11 upper:

Instead of @GET(...) / @POST(...)

Do @HTTP(method = "get", path = "/user/get", hasBody = true) - use lowercase get!

So it’s start look like:

@HTTP(method = "get", path = "/user/get", hasBody = true) suspend fun transcripts(@Body request: TranscriptsRequest): TranscriptsResponse

Perfectly works!

a well-known open source library that is opinionated , closed, and ignores standard protocols

OkHttp is an opinionated HTTP client. By constraining what we support to what the specs allow, we’re able to keep things relatively simple and offer great features like smart caching.

Nice. Opinionated on a standard. lol

For me it’s fundamentally that OkHttp is an opionated user agent, not a toolkit that aims to supports all use cases. For example, we follow the security changes that browsers make over time, such that each upgrade potentially breaks some clients because it forces people to upgrade security. It would be easier to try to keep everything working, but sometimes it’s the right thing to do to put pressure for other systems to fix.

@yschimke Those docs say one thing however on experimentation putting the query in the url parameters rather than the body of a GET request returns a “code 400 Bad Request” error: Screen Shot 2022-06-08 at 6 03 14 AM

That being said, I’ve just found the same query can be performed with a POST request rather than a GET request: Screen Shot 2022-06-08 at 5 57 13 AM

Which is what I suppose I’ll be using for the time being. The only downsides are that this request takes longer to return a response than the equivalent GET request, and also I’d generally consider a GraphQL query to be more of a GET style request than a POST request, but I’ll do whatever works.

Interesting question. It seems that the XMLHttpRequest spec specifies to actively ignore any body parameters attached to a GET request. So OkHttp is in line with the XHR spec at least in this regard.

If that’s a standard to get parity for, then there goes the argument. It’s worth noting that this standard stems from before the updates to the HTTP RFCs, but there you go.

Code exists that assumes GET requests don’t have a body. If that invariant is changed, this code may no longer be correct.

Interceptors: an interceptor implementing a cache (not OkHttp’s built-in cache) might not pay attention to the request body field (it’s not supposed to exist!) and treat all request bodies as equivalent with respect to caching. This would be bad.

Request smuggling: you implement a Java Servlet that takes the incoming servlet request and builds an OkHttp request from it, then forwards that on to an internal webservice. Previously those internal web services never had GETs with bodies; now they do. If those things don’t attempt to read and discard the request body, then you might be able to smuggle a 2nd request through the first request’s body.

Typically OkHttp’s invariants are there to prevent developers from doing incorrect things by accident. But they have another purpose; they allow developers to assume incorrect things aren’t going to get through when they aren’t directly creating the requests. If we change the rules, then code that was relying on those rules being enforced may break.

In some ways issue #4865 is similar. Allowing OkHttp to express which local network interface is used fixes a bug, but creates the possibility for many more.