ruby-concurrency/concurrent-ruby · error · ArgumentError
#{value} is not an Integer
Error message
#{value} is not an Integer What it means
The native-integer guard requires actual Integer inputs: anything else (String, Float, BigDecimal, nil) raises ArgumentError('x is not an Integer'). It runs in AtomicFixnum.new/#value=/#update and in the constructors of Semaphore, CountDownLatch, and CyclicBarrier. Note that even whole-number Floats like 3.0 are rejected — there is no implicit coercion.
Source
Thrown at lib/concurrent-ruby/concurrent/utility/native_integer.rb:26
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
def ensure_integer_and_bounds(value)
ensure_integer value
ensure_upper_bound value
ensure_lower_bound value
end
def ensure_positive(value)
if value < 0
raise ArgumentError.new("#{value} cannot be negative")
end
value
end
def ensure_positive_and_no_zero(value)View on GitHub (pinned to 0b88d5ff75)
Solutions
- Coerce explicitly at the boundary: count = Integer(value) (Kernel#Integer raises on garbage rather than coercing)
- For trusted numeric strings use value.to_i after a format check like /\A-?\d+\z/
- Check types in config loading: raise TypeError, 'expected Integer' unless v.is_a?(Integer)
Example fix
# before latch = Concurrent::CountDownLatch.new(ENV['WORKERS']) # String -> ArgumentError fix = Concurrent::AtomicFixnum.new(json['offset']) # String # after latch = Concurrent::CountDownLatch.new(Integer(ENV['WORKERS'], 10)) fix = Concurrent::AtomicFixnum.new(Integer(json['offset'], 10))
Defensive patterns
Strategy: type-guard
Validate before calling
count = Integer(value) # Kernel#Integer: strict, raises on garbage Concurrent::CountDownLatch.new(count)
Type guard
def strict_integer?(v) v.is_a?(Integer) end
Try / catch
begin
latch = Concurrent::CountDownLatch.new(raw)
rescue ArgumentError => e
raise unless e.message.include?('not an Integer')
latch = Concurrent::CountDownLatch.new(Integer(raw, 10))
end Prevention
- Convert at boundaries with Kernel#Integer (strict) rather than relying on to_i everywhere
- Freeze expected types in config schemas and validate on load
- Remember 3.0 is rejected too — avoid float arithmetic feeding atomics
When it happens
Trigger: Concurrent::AtomicFixnum.new('42') from ENV/JSON; CountDownLatch.new(3.0) after float division; semaphore = Semaphore.new(params['permits']) where params parsing yields a string; nil passed through a missing config key.
Common situations: Values parsed from YAML/JSON/ENV that arrive as strings; arithmetic that mixes Floats (n / 2.0, BigDecimal money math) and is stored into an atomic; user input forwarded without conversion.
Related errors
- no block given
- Not all dependencies are IVars. Dependencies: #{ inputs.insp
- no block given
- number of threads must be greater than zero
- no block given
AI-assisted analysis of ruby-concurrency/concurrent-ruby@0b88d5ff75 (2026-08-21).
Data as JSON: /api/errors/ce61c4bdf29a2514.
Report an issue: GitHub.