Skip to content

unexpected ArgumentError: wrong number of arguments #9281

@kares

Description

@kares

Environment Information

Provide at least:

  • JRuby version (jruby -v) 10.0.2.0 / 10.0.3.0 both -Xcompile.invokedynamic=true/false
  • Java 21

First, the assumption was the issue is JRuby JIT related, we still do not have much useful info from production.

There seems to be an AI reproducer script that confirms kwargs issue regarding:

Root cause: IRRuntimeHelpers.setCallInfo() unconditionally preserves the CALL_KEYWORD_EMPTY bit from context.callInfo, even when it is stale from a prior unrelated call

Here's a failing script that passed on MRI 3.4.8 but fails under JRuby

ruby 3.4.8 (2025-12-17 revision 995b59f666) +PRISM [x86_64-linux]
Pattern 1: Contamination before .new
  Control (no Dir call):     [1, 2]
  Bug (after Dir[**{}]):     [1, 2]
  Control (Dir[**{sort:}]):  [1, 2]

Pattern 2: Contamination inside initialize (super)
  Result: [1, 2]
  Control (non-empty extra): [1, 2]
# Triggers on ALL dispatch paths (interpreter, JIT, indy)
# because Dir.[] is keywords=true — neither the wrapper nor finishBinding ever clears callInfo for it.

class Victim
  def initialize(a, k:)
    @a = a
    @k = k
  end

  def result
    [@a, @k]
  end
end

# -- Pattern 1: Contamination before .new ----------------------------------

def control_constructor
  v = Victim.new(1, k: 2)
  puts "  Control (no Dir call):     #{v.result.inspect}"
end

def bug_constructor(options)
  Dir["nonexistent_pattern", **options]
  v = Victim.new(1, k: 2)
  puts "  Bug (after Dir[**{}]):     #{v.result.inspect}"
end

def control_nonempty(options)
  Dir["nonexistent_pattern", **options]
  v = Victim.new(1, k: 2)
  puts "  Control (Dir[**{sort:}]):  #{v.result.inspect}"
end

# -- Pattern 2: Contamination inside initialize via super -------------------

class Base
  def initialize(a, k:)
    @a = a
    @k = k
  end

  def result
    [@a, @k]
  end
end

class Child < Base
  def initialize(a, k:, **extra)
    Dir["nonexistent_pattern", **extra]
    super(a, k: k)
  end
end

# -- Run tests --------------------------------------------------------------

puts "Pattern 1: Contamination before .new"

control_constructor

begin
  bug_constructor({})
rescue ArgumentError => e
  puts "  BUG TRIGGERED: #{e.message}"
  puts "    #{e.backtrace.first(3).join("\n    ")}"
end

control_nonempty({sort: false})

puts
puts "Pattern 2: Contamination inside initialize (super)"

begin
  puts "  Result: #{Child.new(1, k: 2).result.inspect}"
rescue ArgumentError => e
  puts "  BUG TRIGGERED: #{e.message}"
  puts "    #{e.backtrace.first(3).join("\n    ")}"
end

puts "  Control (non-empty extra): #{Child.new(1, k: 2, sort: false).result.inspect}"

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions