-
Notifications
You must be signed in to change notification settings - Fork 25.6k
Description
We had users report that their application using the Java client was working fine with ES 9.0, but that some API calls were failing with 9.1. After some investigation, @l-trotta and found it was caused by PR #129302, released in 9.1.
This PR changed how Request.hasContent() is implemented. This is causing issues with some POST requests with no body and no Content-Type header, in particular http/2 requests relayed by the Cloud proxy (and converted to http/1). The ES server will assume these requests have a content while they actually do not.
If these requests do not have a Content-Type header, API version compatibility will fail and the request will be rejected.
Steps to reproduce
Create a 9.0.0 cluster on Elastic Cloud, and run this command (adding -v will show that http/2 is used):
curl -X POST \
-H "Authorization: ApiKey <redacted> \
-H "Accept: application/vnd.elasticsearch+json; compatible-with=9" \
"https://<cluster-id>.elastic-cloud.com/_count"
{"count":103,"_shards":{"total":18,"successful":18,"skipped":0,"failed":0}}
Run that same command on a 9.1.0 cluster. It fails, indicating that a Content-Type=null is not compatible with the Accept header value:
{"error":{"root_cause":[{"type":"media_type_header_exception","reason":"Invalid media-type value on headers [Accept, Content-Type]"}],"type":"media_type_header_exception","reason":"Invalid media-type value on headers [Accept, Content-Type]","caused_by":{"type":"status_exception","reason":"A compatible version is required on both Content-Type and Accept headers if either one has requested a compatible version. Accept=application/vnd.elasticsearch+json; compatible-with=9, Content-Type=null"}},"status":400}
Adding ?error_trace=true shows the root exception:
Caused by: org.elasticsearch.ElasticsearchStatusException: A compatible version is required on both Content-Type and Accept headers if either one has requested a compatible version. Accept=application/vnd.elasticsearch+json; compatible-with=9, Content-Type=null
at [email protected]/org.elasticsearch.rest.RestCompatibleVersionHelper.getCompatibleVersion(RestCompatibleVersionHelper.java:76)
This exception means that contentTypeHeader is null as expected, but that hasContent is true which isn't expected. This probably comes from HttpBody.isEmpty() where the body is likely set, and to a HttpBody.Stream instance.
Workarounds
There are some workarounds, although they can be considered counter-intuitive:
- Force http/1: add
--http1.1to the curl command. Most modern http clients will automatically negotiate and upgrade to http/2 when available. Works with Elastic Cloud, but may not be effective in all environments. - Add a
Content-Typeheader: add-H 'Content-Type: application/vnd.elasticsearch+json; compatible-with=9to the curl command. Many users and client libraries will not add aContent-Typeto an empty request.
Note that setting Content-Length: 0 doesn't solve the issue.