apache/cassandra · error · IllegalArgumentException

is already bound in reverseMap to

Error message

${value} is already bound in reverseMap to ${oldKey}

What it means

ConcurrentBiMap enforces bijective key<->value mapping. put() first checks the reverse map: if the value is already bound to a different key, adding it again would break uniqueness, so it throws IllegalArgumentException naming the value and the existing key.

Solutions

  1. Ensure values are unique before inserting; generate fresh unique values (UUIDs, ports) per key
  2. If re-binding is intended, remove the old key's entry first (map.remove(oldKey)) then put
  3. Catch IllegalArgumentException to detect duplicate value registration and handle it at the application layer

Example fix

// before
biMap.put("node2", existingValue); // throws
// after
biMap.remove("node1"); // release old binding
biMap.put("node2", existingValue);
Defensive patterns

Strategy: try-catch

Validate before calling

boolean safePut(ConcurrentBiMap<K,V> map, K key, V value) {
    return !map.containsValue(value) || key.equals(map.inverse().get(value));
}

Try / catch

try {
    map.put(key, value);
} catch (IllegalArgumentException e) {
    // value already bound to another key — decide: skip, replace, or generate new value
}

Prevention

When it happens

Trigger: map.put("host1", "tokenA") followed by map.put("host2", "tokenA") — the same value bound under two different keys.

Common situations: Registering endpoints/resources where two logical names accidentally map to the same underlying value (duplicate IP:port, shared token, same UUID reused across entries).

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10). Data as JSON: /api/errors/48f3e11632306ae1. Report an issue: GitHub.

Appendix: source

Thrown at src/java/org/apache/cassandra/utils/ConcurrentBiMap.java:97

    {
        return forwardMap.get(key);
    }

    public boolean isEmpty()
    {
        return forwardMap.isEmpty();
    }

    public Set<K> keySet()
    {
        return forwardMap.keySet();
    }

    public synchronized V put(K key, V value)
    {
        K oldKey = reverseMap.get(value);
        if (oldKey != null && !key.equals(oldKey))
            throw new IllegalArgumentException(value + " is already bound in reverseMap to " + oldKey);
        V oldVal = forwardMap.put(key, value);
        if (oldVal != null && !Objects.equals(reverseMap.remove(oldVal), key))
            throw new IllegalStateException(); // for the prior mapping to be correct, we MUST get back the key from the reverseMap
        reverseMap.put(value, key);
        return oldVal;
    }

    public synchronized void putAll(Map<? extends K, ? extends V> m)
    {
        for (Entry<? extends K, ? extends V> entry : m.entrySet())
            put(entry.getKey(), entry.getValue());
    }

    public synchronized V remove(Object key)
    {
        V oldVal = forwardMap.remove(key);
        if (oldVal == null)
            return null;

View on GitHub (pinned to 88fd0f6a0e)