From 15ece5af2963e340ae61bd6cd76456b750eb07d5 Mon Sep 17 00:00:00 2001 From: Fernando Briano Date: Wed, 17 Jun 2026 12:44:38 +0100 Subject: [PATCH 1/2] Backports #2984 - Fixes header conflict on Serverless When a client also sets the Elastic-Api-Version header (required for Elasticsearch Serverless), serverless rejects the request with HTTP 400: The request includes both the [Elastic-Api-Version] header and a [compatible-with] parameter, but it is not valid to include both of these in a request These two versioning mechanisms serve different deployment models and are mutually exclusive on the server side: * compatible-with=N: REST API compatibility for self-managed/hosted major version upgrades * Elastic-Api-Version: 2023-10-31: date-based API versioning for serverless With this change, set_content_type! checks if Elastic-Api-Version is already present in transport_options[:headers] for adding compatible-with headers. Addresses #2983 Use safe navigation operator to check for API version header Co-authored-by: Kaise <69120390+kaisecheng@users.noreply.github.com> [Tests] Skips jbuilder for specific version of JRuby There is a dependency issue with JBuilder and JRuby 9.4.15.0 at the moment. This breaks the build unrelated to recent changes. A patch release is needed, so will investigate. NoMethodError: undefined method `[]' for Fiber:Class --- .github/workflows/otel.yml | 4 ++-- elasticsearch-api/spec/spec_helper.rb | 8 ++++++- .../spec/unit/actions/json_builders_spec.rb | 3 ++- elasticsearch/lib/elasticsearch.rb | 8 +++++-- elasticsearch/spec/unit/headers_spec.rb | 22 +++++++++++++++++++ 5 files changed, 39 insertions(+), 6 deletions(-) diff --git a/.github/workflows/otel.yml b/.github/workflows/otel.yml index f735fde751..ee3943f291 100644 --- a/.github/workflows/otel.yml +++ b/.github/workflows/otel.yml @@ -2,10 +2,10 @@ name: opentelemetry on: push: branches: - - main + - 9.3 pull_request: branches: - - main + - 9.3 jobs: test-otel: name: 'Test Open Telemetry' diff --git a/elasticsearch-api/spec/spec_helper.rb b/elasticsearch-api/spec/spec_helper.rb index aa79707a33..0424408c52 100644 --- a/elasticsearch-api/spec/spec_helper.rb +++ b/elasticsearch-api/spec/spec_helper.rb @@ -28,12 +28,18 @@ end require 'elasticsearch' require 'elasticsearch-api' -require 'jbuilder' require 'jsonify' require 'logger' require 'openssl' require 'yaml' +# TODO: There is a dependency issue with JRuby 9.4.15.0 and JBuilder at the moment: +def jruby_exception? + defined?(JRUBY_VERSION) && + JRUBY_VERSION.between?('9.4', '9.5') +end +require 'jbuilder' unless jruby_exception? + tracer = ::Logger.new(STDERR) tracer.formatter = lambda { |s, d, p, m| "#{m.gsub(/^.*$/) { |n| ' ' + n } }\n" } diff --git a/elasticsearch-api/spec/unit/actions/json_builders_spec.rb b/elasticsearch-api/spec/unit/actions/json_builders_spec.rb index 899674590e..db97f1a808 100644 --- a/elasticsearch-api/spec/unit/actions/json_builders_spec.rb +++ b/elasticsearch-api/spec/unit/actions/json_builders_spec.rb @@ -83,4 +83,5 @@ expect(client_double.search(body: json)).to be_a Elasticsearch::API::Response end end -end +end unless jruby_exception? +# TODO: Exception for JRuby v9.4.15.0 ^ diff --git a/elasticsearch/lib/elasticsearch.rb b/elasticsearch/lib/elasticsearch.rb index e27c79cd45..e8ea177ce9 100644 --- a/elasticsearch/lib/elasticsearch.rb +++ b/elasticsearch/lib/elasticsearch.rb @@ -189,15 +189,19 @@ def set_user_agent!(arguments) def set_content_type!(arguments) headers = {} user_headers = arguments&.[](:transport_options)&.[](:headers) - unless user_headers&.keys&.detect { |h| h =~ /content-?_?type/i } + unless user_headers&.keys&.detect { |h| h =~ /content-?_?type/i } || api_version_set?(user_headers) headers['content-type'] = 'application/vnd.elasticsearch+json; compatible-with=9' end - unless user_headers&.keys&.detect { |h| h =~ /accept/i } + unless user_headers&.keys&.detect { |h| h =~ /accept/i } || api_version_set?(user_headers) headers['accept'] = 'application/vnd.elasticsearch+json; compatible-with=9' end set_header(headers, arguments) unless headers.empty? end + def api_version_set?(headers) + !!headers&.keys&.find { |a| a.match?(/elastic-api-version/i) } + end + def set_header(header, arguments) arguments[:transport_options] ||= {} arguments[:transport_options][:headers] ||= {} diff --git a/elasticsearch/spec/unit/headers_spec.rb b/elasticsearch/spec/unit/headers_spec.rb index a6155032d8..da072651df 100644 --- a/elasticsearch/spec/unit/headers_spec.rb +++ b/elasticsearch/spec/unit/headers_spec.rb @@ -142,4 +142,26 @@ client.search end end + + context 'when Elastic-Api-Version header is set' do + let!(:client) do + described_class.new( + host: 'http://localhost:9200', + transport_options: { headers: { 'Elastic-Api-Version' => '2023-10-31' } } + ).tap do |client| + client.instance_variable_set('@verified', true) + end + end + + it 'does not modify the content-type header' do + expected_headers = client.transport.connections.connections.first.connection.headers + expect(expected_headers['Content-Type']).to eq 'application/json' + expect(expected_headers['Elastic-Api-Version']).to eq '2023-10-31' + + expect_any_instance_of(Faraday::Connection) + .to receive(:run_request) + .with(:get, 'http://localhost:9200/_search', nil, expected_headers) { OpenStruct.new(body: '') } + client.search + end + end end From a964e5befd1ba9b20c0060e24e8a0d7de8d02b43 Mon Sep 17 00:00:00 2001 From: Fernando Briano Date: Wed, 17 Jun 2026 16:14:57 +0100 Subject: [PATCH 2/2] Bumps version to 9.3.4 and updates CHANGELOG --- CHANGELOG.md | 4 ++++ elasticsearch-api/lib/elasticsearch/api/version.rb | 2 +- elasticsearch/elasticsearch.gemspec | 2 +- elasticsearch/lib/elasticsearch/version.rb | 2 +- 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 899a24e1c8..628e3520ff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ **See the full release notes on the official documentation website: https://www.elastic.co/docs/release-notes/elasticsearch/clients/ruby** +# 9.3.4 + +* Fixes header conflict when using Elasticsearch Serverless. [Pull Request](https://github.com/elastic/elasticsearch-ruby/pull/2984) + # 9.3.3 * Fixes NoMethodError when `Content-Type` lacks `compatible-with` parameter. [Pull Request](https://github.com/elastic/elasticsearch-ruby/pull/2974) diff --git a/elasticsearch-api/lib/elasticsearch/api/version.rb b/elasticsearch-api/lib/elasticsearch/api/version.rb index 3cfc43557c..83d5a64a3c 100644 --- a/elasticsearch-api/lib/elasticsearch/api/version.rb +++ b/elasticsearch-api/lib/elasticsearch/api/version.rb @@ -17,7 +17,7 @@ module Elasticsearch module API - VERSION = '9.3.3'.freeze + VERSION = '9.3.4'.freeze ES_SPECIFICATION_COMMIT = '31789f4216047ef7ba7969e31610fa2bbfe696b1'.freeze end end diff --git a/elasticsearch/elasticsearch.gemspec b/elasticsearch/elasticsearch.gemspec index ca6080135d..5130dc5b8e 100644 --- a/elasticsearch/elasticsearch.gemspec +++ b/elasticsearch/elasticsearch.gemspec @@ -46,7 +46,7 @@ Gem::Specification.new do |s| s.rdoc_options = ['--charset=UTF-8'] s.required_ruby_version = '>= 2.6' # For compatibility with JRuby 9.3 - s.add_dependency 'elasticsearch-api', '9.3.3' + s.add_dependency 'elasticsearch-api', '9.3.4' s.add_dependency 'elastic-transport', '~> 8.3' s.add_development_dependency 'base64' diff --git a/elasticsearch/lib/elasticsearch/version.rb b/elasticsearch/lib/elasticsearch/version.rb index 799a015d8e..a5879b66a9 100644 --- a/elasticsearch/lib/elasticsearch/version.rb +++ b/elasticsearch/lib/elasticsearch/version.rb @@ -16,5 +16,5 @@ # under the License. module Elasticsearch - VERSION = '9.3.3'.freeze + VERSION = '9.3.4'.freeze end