ruby-concurrency/concurrent-ruby · error · RangeError

#{value} is greater than the maximum value of #{MAX_VALUE}

Error message

#{value} is greater than the maximum value of #{MAX_VALUE}

What it means

Concurrent::Utility::NativeInteger guards native-backed primitives (AtomicFixnum, Semaphore, CountDownLatch, CyclicBarrier) against values that exceed what a native fixnum slot holds: 2**62 - 1 on 64-bit MRI. Ruby Integers are arbitrary precision, so large results compute silently and only blow up when stored into one of these primitives as RangeError. AtomicFixnum.new, AtomicFixnum#value=, and #update all pass through this check.

Source

Thrown at lib/concurrent-ruby/concurrent/utility/native_integer.rb:12

module Concurrent
  # @!visibility private
  module Utility
    # @private
    module NativeInteger
      # http://stackoverflow.com/questions/535721/ruby-max-integer
      MIN_VALUE = -(2**(0.size * 8 - 2))
      MAX_VALUE = (2**(0.size * 8 - 2) - 1)

      def ensure_upper_bound(value)
        if value > MAX_VALUE
          raise RangeError.new("#{value} is greater than the maximum value of #{MAX_VALUE}")
        end
        value
      end

      def ensure_lower_bound(value)
        if value < MIN_VALUE
          raise RangeError.new("#{value} is less than the maximum value of #{MIN_VALUE}")
        end
        value
      end

      def ensure_integer(value)
        unless value.is_a?(Integer)
          raise ArgumentError.new("#{value} is not an Integer")
        end
        value
      end

View on GitHub (pinned to 0b88d5ff75)

Solutions

  1. Validate before storing: raise RangeError, 'counter overflow' if value > Concurrent::Utility::NativeInteger::MAX_VALUE
  2. Keep oversized counters in a plain Integer guarded by a Mutex or use two counters (high/low words) instead of AtomicFixnum
  3. Clamp if saturation is acceptable: value = [value, MAX_VALUE].min (document the saturation)

Example fix

# before
counter = Concurrent::AtomicFixnum.new(2**63) # RangeError

# after
max = Concurrent::Utility::NativeInteger::MAX_VALUE
raise RangeError, 'id too large for atomic counter' if id > max
counter = Concurrent::AtomicFixnum.new(id)
Defensive patterns

Strategy: validation

Validate before calling

NI = Concurrent::Utility::NativeInteger
raise RangeError, "#{value} exceeds atomic counter range" if value.is_a?(Integer) && value > NI::MAX_VALUE
Concurrent::AtomicFixnum.new(value)

Type guard

def native_int?(v)
  v.is_a?(Integer) &&
    v.between?(Concurrent::Utility::NativeInteger::MIN_VALUE,
               Concurrent::Utility::NativeInteger::MAX_VALUE)
end

Try / catch

begin
  counter.value = next_value
rescue RangeError
  counter.value = Concurrent::Utility::NativeInteger::MAX_VALUE # explicit saturation + alert
end

Prevention

When it happens

Trigger: Concurrent::AtomicFixnum.new(2**63); counter.update { |v| v * 2 } crossing the bound; bit masks like (1 << 63) stored into an AtomicFixnum; IDs/counters aggregated over a long-lived process.

Common situations: Shard/snowflake-style IDs or epoch-millisecond counters pushed into AtomicFixnum; multiplying large aggregates in update blocks; porting code from JRuby (where native limits differ) to MRI.

Related errors


AI-assisted analysis of ruby-concurrency/concurrent-ruby@0b88d5ff75 (2026-08-21). Data as JSON: /api/errors/4dd486c5c15ba89d. Report an issue: GitHub.