TheAlgorithms/Java · error · IllegalArgumentException
Key and value must not be null
Error message
Key and value must not be null
What it means
Thrown by FIFOCache.put(K, V, long) when either the key or the value is null. The cache stores entries in a HashMap and notifies an eviction listener on overwrite, so a null value would be ambiguous with an absent/expired entry. The check fires before lock acquisition and before any TTL validation.
Source
Thrown at src/main/java/com/thealgorithms/datastructures/caches/FIFOCache.java:166
put(key, value, defaultTTL);
}
/**
* Adds a key-value pair to the cache with a specified time-to-live (TTL).
*
* <p>If the key already exists, its value is removed, re-inserted at tail and its TTL is reset.
* If the key does not exist and the cache is full, the oldest entry is evicted to make space.
* Expired entries are also cleaned up prior to any eviction. The eviction listener
* is notified when an entry gets evicted.
*
* @param key the key to associate with the cached value; must not be {@code null}
* @param value the value to be cached; must not be {@code null}
* @param ttlMillis the time-to-live for this entry in milliseconds; must be >= 0
* @throws IllegalArgumentException if {@code key} or {@code value} is {@code null}, or if {@code ttlMillis} is negative
*/
public void put(K key, V value, long ttlMillis) {
if (key == null || value == null) {
throw new IllegalArgumentException("Key and value must not be null");
}
if (ttlMillis < 0) {
throw new IllegalArgumentException("TTL must be >= 0");
}
lock.lock();
try {
// If key already exists, remove it
CacheEntry<V> oldEntry = cache.remove(key);
if (oldEntry != null && !oldEntry.isExpired()) {
notifyEviction(key, oldEntry.value);
}
// Evict expired entries to make space for new entry
evictExpired();
// If no expired entry was removed, remove the oldest
if (cache.size() >= capacity) {View on GitHub (pinned to fdfb9a395b)
Solutions
- Skip caching when the computed value is null: if (value != null) cache.put(key, value, ttl);
- Represent 'absent' with a sentinel/Optional rather than null.
- Validate both key and value at the service boundary.
Example fix
// before cache.put(id, repo.find(id), ttl); // after V value = repo.find(id); if (id != null && value != null) cache.put(id, value, ttl);
Defensive patterns
Strategy: validation
Validate before calling
if (key == null || value == null) {
// do not cache; log if unexpected
return;
}
cache.put(key, value, ttlMillis); Type guard
static <K, V> boolean isCacheable(K key, V value) {
return key != null && value != null;
} Prevention
- Do not cache repository results that can legitimately be absent; treat null as 'do not cache'.
- Use a sentinel or Optional to represent absence.
- Validate both key and value at the service boundary.
When it happens
Trigger: cache.put(key, null, ttl); cache.put(null, value, ttl); inserting the result of a computation that legitimately returned null; deserialized DTOs whose optional fields default to null.
Common situations: Caching the result of a repository lookup that can legitimately be absent; test fixtures that forget to set a field; ORM mappings that yield null for unset columns.
Related errors
- Key must not be null
- Key cannot be null
- Listener must not be null
- Eviction strategy must not be null
- TTL must be >= 0
AI-assisted analysis of TheAlgorithms/Java@fdfb9a395b (2026-08-13).
Data as JSON: /api/errors/1c4e26ac54ad7ffc.
Report an issue: GitHub.