ruby-concurrency/concurrent-ruby · error · ArgumentError
size must be greater than 0
Error message
size must be greater than 0
What it means
Concurrent::Channel::Buffer::Buffered is the bounded FIFO buffer behind buffered channels. Its ns_initialize coerces size with to_i and requires the result to be positive, because a bounded queue with zero or negative capacity cannot exist; 0.5.to_i == 0, so fractional sizes also raise. Note that Channel.new(buffer: :buffered, capacity: 0) never reaches this - channel.rb maps that combination to an unbuffered buffer; direct Buffer construction has no such mapping.
Source
Thrown at lib/concurrent-ruby-edge/concurrent/channel/buffer/buffered.rb:89
def poll
synchronize do
if ns_empty?
Concurrent::NULL
else
buffer.shift
end
end
end
private
# @!macro channel_buffer_initialize
#
# @param [Integer] size the maximum capacity of the buffer; must be
# greater than zero.
# @raise [ArgumentError] when the size is zero (0) or less.
def ns_initialize(size)
raise ArgumentError.new('size must be greater than 0') if size.to_i <= 0
self.capacity = size.to_i
self.buffer = []
end
# @!macro channel_buffer_size_reader
def ns_size
buffer.size
end
# @!macro channel_buffer_empty_question
def ns_empty?
ns_size == 0
end
# @!macro channel_buffer_full_question
def ns_full?
ns_size == capacity
endView on GitHub (pinned to 0b88d5ff75)
Solutions
- Pass a positive integer size: Concurrent::Channel::Buffer::Buffered.new(10).
- Default and validate config-derived sizes before construction, failing loudly at startup rather than deep in a worker thread.
- For zero-capacity rendezvous semantics use Buffer::Unbuffered (or an unbuffered Channel).
Example fix
# before
buffer = Concurrent::Channel::Buffer::Buffered.new(ENV.fetch('QUEUE_SIZE', 0).to_i)
# after
size = ENV.fetch('QUEUE_SIZE', 1).to_i
raise ArgumentError, 'QUEUE_SIZE must be >= 1' if size < 1
buffer = Concurrent::Channel::Buffer::Buffered.new(size) Defensive patterns
Strategy: validation
Validate before calling
size = Integer(size_param) raise ArgumentError, 'buffer size must be >= 1' if size < 1 buffer = Concurrent::Channel::Buffer::Buffered.new(size)
Try / catch
begin
buffer = Concurrent::Channel::Buffer::Buffered.new(size)
rescue ArgumentError => e
raise ConfigError, "bad buffer size #{size.inspect}: #{e.message}"
end Prevention
- to_i runs first: 0.5 and nil-adjacent values collapse to 0 and raise - validate the original value.
- Default size keys to 1 (or fail) in config loading; never let 0 mean unbounded.
- Prefer Channel.new(buffer: :buffered, capacity: n) over raw Buffer objects unless you need injection.
When it happens
Trigger: Concurrent::Channel::Buffer::Buffered.new(0), .new(-1), or .new(0.5); also building channels by injecting a raw buffer (Channel.new(some_buffer)) where the buffer was constructed with a config-derived size that is 0 or nil.
Common situations: Capacity from ENV/config whose default converts to 0 when missing (ENV.fetch('QUEUE_SIZE', 0).to_i); reusing a capacity constant that was set to 0 to mean 'unbounded'; tests constructing buffers with placeholder sizes.
Related errors
- capacity must be at least 1 for this buffer type
- unbuffered channels cannot have a capacity
- no block given
- invalid action
- no block given
AI-assisted analysis of ruby-concurrency/concurrent-ruby@0b88d5ff75 (2026-08-21).
Data as JSON: /api/errors/529b6cf9eb0378d7.
Report an issue: GitHub.