ruby/ruby · error · ArgumentError

mem_size must be a Integer

Error message

mem_size must be a Integer

What it means

RubyVM::YJIT.enable validates the mem_size keyword (executable code area size, in MB) and requires a true Integer. Strings ('128') and Floats — including whole-valued ones like 64.0 — fail mem_size.is_a?(Integer) and raise ArgumentError. The same value must then be within 1..2048, but that is a separate check.

Source

Thrown at yjit.rb:57

  #
  # * `stats`:
  #     * `false`: Don't enable stats.
  #     * `true`: Enable stats. Print stats at exit.
  #     * `:quiet`: Enable stats. Do not print stats at exit.
  # * `log`:
  #     * `false`: Don't enable the log.
  #     * `true`: Enable the log. Print log at exit.
  #     * `:quiet`: Enable the log. Do not print log at exit.
  def self.enable(stats: false, log: false, mem_size: nil, call_threshold: nil)
    return false if enabled?

    if Primitive.cexpr! 'RBOOL(rb_zjit_enabled_p)'
      warn("Only one JIT can be enabled at the same time.")
      return false
    end

    if mem_size
      raise ArgumentError, "mem_size must be a Integer" unless mem_size.is_a?(Integer)
      raise ArgumentError, "mem_size must be between 1 and 2048 MB" unless (1..2048).include?(mem_size)
    end

    if call_threshold
      raise ArgumentError, "call_threshold must be a Integer" unless call_threshold.is_a?(Integer)
      raise ArgumentError, "call_threshold must be a positive integer" unless call_threshold.positive?
    end

    at_exit { print_and_dump_stats } if stats
    Primitive.rb_yjit_enable(stats, stats != :quiet, log, log != :quiet, mem_size, call_threshold)
  end

  # If --yjit-trace-exits is enabled parse the hashes from
  # Primitive.rb_yjit_get_exit_locations into a format readable
  # by Stackprof. This will allow us to find the exact location of a
  # side exit in YJIT based on the instruction that is exiting.
  def self.exit_locations # :nodoc:
    return unless trace_exit_locations_enabled?

View on GitHub (pinned to 0e5b888e1c)

Solutions

  1. Coerce at the boundary: mem_size: value&.to_i for trusted config, or Integer(value) for strict parsing
  2. Pass an Integer literal within the documented 1..2048 range
  3. Validate config types once at load time (ENV schema, dry-validation) so YJIT.enable never sees strings

Example fix

# before
RubyVM::YJIT.enable(mem_size: ENV['YJIT_MEM_SIZE'])  # String from ENV -> ArgumentError

# after
RubyVM::YJIT.enable(mem_size: ENV['YJIT_MEM_SIZE']&.to_i)  # nil or Integer
Defensive patterns

Strategy: type-guard

Validate before calling

mem = config.fetch(:yjit_mem_size, nil)
mem = Integer(mem) if mem.is_a?(String)  # strict cast; raises early on garbage
RubyVM::YJIT.enable(mem_size: mem) if mem.nil? || mem.is_a?(Integer)

Type guard

# Exact check YJIT itself performs; note Float 64.0 is rejected by design
def yjit_integer?(v)
  v.is_a?(Integer)
end

Try / catch

begin
  RubyVM::YJIT.enable(mem_size: mem)
rescue ArgumentError => e
  warn "YJIT config rejected (#{e.message}); enabling with defaults"
  RubyVM::YJIT.enable
end

Prevention

When it happens

Trigger: RubyVM::YJIT.enable(mem_size: '128') with a String from ENV or YAML config; mem_size: 64.0 produced by a Float computation or JSON number parsing; any truthy non-Integer (nil is allowed and skips validation).

Common situations: Reading mem_size from ENV variables or YAML without to_i; arithmetic that produced Floats (64.0/1); JSON configs whose numbers parse as Float.

Related errors


AI-assisted analysis of ruby/ruby@0e5b888e1c (2026-08-21). Data as JSON: /api/errors/7b087e32b4cfe1f5. Report an issue: GitHub.