ruby-concurrency/concurrent-ruby · error · IllegalArgumentException
IllegalArgumentException
Error message
IllegalArgumentException
What it means
The single-argument constructor treats initialCapacity as a sizing hint and converts it to a power-of-two table size via tableSizeFor. A negative capacity cannot be a table size, so the constructor throws IllegalArgumentException before any table is allocated. The exception carries no message; the stack frame at this constructor line is the only diagnostic.
Source
Thrown at ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/ConcurrentHashMapV8.java:2536
* Creates a new, empty map with the default initial table size (16).
*/
public ConcurrentHashMapV8() {
this.counter = new LongAdder();
}
/**
* Creates a new, empty map with an initial table size
* accommodating the specified number of elements without the need
* to dynamically resize.
*
* @param initialCapacity The implementation performs internal
* sizing to accommodate this many elements.
* @throws IllegalArgumentException if the initial capacity of
* elements is negative
*/
public ConcurrentHashMapV8(int initialCapacity) {
if (initialCapacity < 0)
throw new IllegalArgumentException();
int cap = ((initialCapacity >= (MAXIMUM_CAPACITY >>> 1)) ?
MAXIMUM_CAPACITY :
tableSizeFor(initialCapacity + (initialCapacity >>> 1) + 1));
this.counter = new LongAdder();
this.sizeCtl = cap;
}
/**
* Creates a new map with the same mappings as the given map.
*
* @param m the map
*/
public ConcurrentHashMapV8(Map<? extends K, ? extends V> m) {
this.counter = new LongAdder();
this.sizeCtl = DEFAULT_CAPACITY;
internalPutAll(m);
}
View on GitHub (pinned to 0b88d5ff75)
Solutions
- Clamp before constructing: use Math.max(0, requestedCapacity) or fall back to a default like 16 when negative
- Validate numeric configuration once at load time and fail fast with a clear message instead of at first construction
- Treat the -1 sentinel as an instruction to use the no-arg constructor
Example fix
// before int cap = configuredCapacity; // -1 when unset new ConcurrentHashMapV8<String,String>(cap); // after int cap = configuredCapacity > 0 ? configuredCapacity : 16; new ConcurrentHashMapV8<String,String>(cap);
Defensive patterns
Strategy: validation
Validate before calling
int cap = (configuredCapacity != null && configuredCapacity > 0) ? configuredCapacity : DEFAULT_CAPACITY; // then construct with cap
Try / catch
try { new ConcurrentHashMapV8<K,V>(cap); } catch (IllegalArgumentException e) { throw new ConfigException(cap); } Prevention
- Validate numeric config once at startup, not at each construction
- Convert the -1 unset sentinel to a default before constructing
- Clamp any arithmetic on sizes before passing them as capacity
When it happens
Trigger: new ConcurrentHashMapV8<K,V>(-1); passing a computed size such as expected - slack that underflows below zero; forwarding a configuration value that uses -1 as its unset sentinel straight into the constructor.
Common situations: Plumbing capacity from YAML/env/config where the default is -1 meaning not-set; boundary-value unit tests; refactoring HashMap initialCapacity code paths into the concurrent map during a caching migration.
Related errors
- capacity must be at least 1 for this buffer type
- size must be greater than 0
- provide only a value or a block
- #{value} cannot be negative
- #{value} cannot be negative or zero
AI-assisted analysis of ruby-concurrency/concurrent-ruby@0b88d5ff75 (2026-08-21).
Data as JSON: /api/errors/7a2ee85c832b7dd0.
Report an issue: GitHub.