Skip to content

NoMethodError when Content-Type lacks compatible-with parameter #2973

Description

@Watson1978

Describe the bug/error/problem
While testing the fluent-plugin-elasticsearch against elasticsearch >= 9.1.2, we encountered a NoMethodError when calling the _bulk API.

It seems that the update_ndjson_headers! method assumes that the Content-Type header always includes the compatible-with= parameter, which causes a crash if a client explicitly sends a pure application/x-ndjson header.

In lib/elasticsearch/api/utils.rb:

version = client_headers[current_content].match(/compatible-with=([0-9]+)/)[1] || 9

If client_headers[current_content] is exactly "application/x-ndjson" (or "application/json"), the regex .match returns nil. Attempting to call [1] on nil triggers the NoMethodError, completely crashing the request before it is sent.

It was introduced at #2759

To Reproduce

require 'bundler/inline'

gemfile do
  source 'https://rubygems.org'
  gem 'elasticsearch', '= 9.1.2'
  # gem 'elasticsearch', '= 9.1.1'
end

require 'elasticsearch'

puts "Elasticsearch Client Version: #{Elasticsearch::VERSION}"
puts "-" * 40

client = Elasticsearch::Client.new(
  url: 'http://localhost:9200',
  transport_options: {
    headers: {
      'Content-Type' => 'application/x-ndjson'
    }
  }
)

client.bulk(body: [
  { index: { _index: 'test_index', _id: '1' } },
  { field: 'value' }
])
  • result:
$ ruby sample.rb
Fetching gem metadata from https://rubygems.org/..........
Resolving dependencies...
Elasticsearch Client Version: 9.1.2
----------------------------------------
/home/watson/.rbenv/versions/4.0.5/lib/ruby/gems/4.0.0/gems/elasticsearch-api-9.1.2/lib/elasticsearch/api/utils.rb:185:in 'Elasticsearch::API::Utils#update_ndjson_headers!': undefined method '[]' for nil (NoMethodError)

        version = client_headers[current_content].match(/compatible-with=([0-9]+)/)[1] || 9
                                                                                   ^^^
        from /home/watson/.rbenv/versions/4.0.5/lib/ruby/gems/4.0.0/gems/elasticsearch-api-9.1.2/lib/elasticsearch/api/actions/bulk.rb:190:in 'Elasticsearch::API::Actions#bulk'
        from sample.rb:23:in '<main>'

Or

irb(main):001> ''.match(/compatible-with=([0-9]+)/)[1]
(irb):1:in '<main>': undefined method '[]' for nil (NoMethodError)
        from <internal:kernel>:168:in 'Kernel#loop'
        from /home/watson/.rbenv/versions/3.4.9/lib/ruby/gems/3.4.0/gems/irb-1.18.0/exe/irb:9:in '<top (required)>'
        from /home/watson/.rbenv/versions/3.4.9/bin/irb:25:in 'Kernel#load'
        from /home/watson/.rbenv/versions/3.4.9/bin/irb:25:in '<main>'

Expected behavior
As Question:

Is it strictly mandatory for clients to include compatible-with=X in the headers for NDJSON endpoints (like _bulk and _msearch) starting from 9.1.2?

  • If it is an unintended regression: Could we fix this by adding a safe navigation operator? (e.g., match(/.../)&.[](1) || 9)
  • If it is strictly required by design: We will update our plugin to explicitly inject the compatible-with parameter to avoid this crash.

Thank you for your time and great work on this gem!

Your Environment (please complete the following information):

  • Operating System any
  • Ruby Version any
  • Elasticsearch client version 9.1.2
  • Elasticsearch version 9.4.2
  • Any other relevant information

Additional context
Add any other context about the problem here.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions