🔴 The Error You're Seeing
Confirm this matches your console output. If it does, you're in the right place.
java.lang.IllegalArgumentException: Illegal initial capacity: -1
at java.base/java.util.HashMap.<init>(HashMap.java:447)
at java.base/java.util.HashMap.<init>(HashMap.java:470)⚡ Quick Fix Works 80% of the time
Clamp computed capacities before constructing.
int cap = Math.max(1, expectedSize);
Map<K, V> map = new HashMap<>((int) (cap / 0.75f) + 1);🧠 Why this Happens
Tap to expand the deep technical explanation
HashMap(int) runs its guards before allocating anything: initialCapacity must be non-negative and at most MAXIMUM_CAPACITY (1 << 30), and loadFactor must be positive and finite ("Illegal load factor" is the sibling message). The value is then rounded up to a power of two during first resize. Negative numbers almost always originate in int arithmetic - dividing by 0.75f after an int multiply overflows, or a sentinel -1 flows from config into the constructor.
The HITEC City Parking Spot Analogy:
Booking a banquet hall for minus forty guests: the reservation desk rejects the form outright instead of guessing.
🔁 How to Reproduce Confirm this is your error
Map<String, Integer> m = new HashMap<>(-1); // IllegalArgumentException
🛠️ Solutions (5 Ways to Fix)
Clamp with Math.max before constructing
👉 Use this if capacity comes from user config or estimates that could be zero/negative.
A one-line lower bound keeps zero legal (zero is fine for HashMap) and blocks negatives from ever reaching the constructor.
int safe = Math.max(0, configuredSize);
Map<String, Config> cache = new HashMap<>(safe);Do the sizing math in long, cast last
👉 Use this if computing capacity as expected * growth / load-factor.
long intermediates cannot overflow int range; validate bounds THEN narrow to int, so impossible values fail your check instead of surfacing here.
long need = (long) expected * 4L / 3L + 1L;
int cap = (need > (1 << 30)) ? (1 << 30) : (int) need;Centralize a sized-map helper
👉 Use this if several call sites compute HashMap capacities.
One static method owns clamping plus the divide-by-load-factor formula; call sites stay honest and tests cover it once.
static <K, V> Map<K, V> withExpectedSize(int n) {
return new HashMap<>((int) ((float) n / 0.75f) + 1);
}Default constructor when size is unknown
👉 Use this if no reliable estimate exists.
new HashMap<>() starts lazily and grows amortized O(1); premature micro-sizing causes more harm than good.
Map<K, V> map = new HashMap<>();Validate configuration at startup
👉 Use this if sizes come from properties/env/yaml.
Fail fast with a message naming the property when parsed sizes fall outside 0..MAXIMUM_CAPACITY, so misconfiguration never reaches collection constructors.
if (configured < 0 || configured > MAX) {
throw new IllegalArgumentException("cache.size invalid: " + configured);
}📋 Version Notes
Same guard and wording; table sized on first resize.
Unchanged wording. Note HashMap(0) is legal and defers allocation until first put.
🛡️ How to Prevent This Next Time
Treat every constructor int argument as untrusted input: clamp or validate at the boundary where the number is born.