quarkusio/quarkus · error · IllegalArgumentException
Key already registered ${key}
Error message
Key already registered ${key} What it means
The registry stores one RuntimeInfo per key using putIfAbsent; if the key already exists it throws IllegalArgumentException('Key already registered <key>'). Registration is first-write-wins — re-registering is treated as a programming error rather than an update.
Source
Thrown at core/runtime/src/main/java/io/quarkus/runtime/ValueRegistryImpl.java:52
if (key == null || key.key() == null) {
throw new IllegalArgumentException("Key cannot be null");
}
if (value == null) {
throw new IllegalArgumentException("Value cannot be null");
}
registerInfo(key, SimpleRuntimeInfo.of(value));
}
public <T> void registerInfo(final RuntimeKey<T> key, final RuntimeInfo<T> runtimeInfo) {
if (key == null || key.key() == null) {
throw new IllegalArgumentException("Key cannot be null");
}
if (runtimeInfo == null) {
throw new IllegalArgumentException("Value cannot be null");
}
RuntimeInfo<?> mapValue = values.putIfAbsent(key.key(), runtimeInfo);
if (mapValue != null) {
throw new IllegalArgumentException("Key already registered " + key.key());
}
}
public <T> boolean containsKey(final RuntimeKey<T> key) {
return values.containsKey(key.key());
}
@SuppressWarnings("unchecked")
public <T> T get(final RuntimeKey<T> key) {
RuntimeInfo<T> runtimeInfo = (RuntimeInfo<T>) values.get(key.key());
if (runtimeInfo == null) {
throw new IllegalArgumentException("Key " + key.key() + " not found");
}
return runtimeInfo.get(this);
}
@SuppressWarnings("unchecked")
public <T> T getOrDefault(final RuntimeKey<T> key, final T defaultValue) {View on GitHub (pinned to e1c734241f)
Solutions
- Guard with registry.containsKey(key) before registering, or use getOrDefault-style access.
- Deduplicate the key: give each registrar a unique key.
- If intentional override is needed, use a different API (clear/replace) rather than register.
Example fix
// before
registry.register(MyKeys.POOL_SIZE, 10);
registry.register(MyKeys.POOL_SIZE, 20); // throws
// after
if (!registry.containsKey(MyKeys.POOL_SIZE)) {
registry.register(MyKeys.POOL_SIZE, 20);
} Defensive patterns
Strategy: validation
Validate before calling
if (!registry.containsKey(key)) {
registry.register(key, value);
} Type guard
boolean isUnregistered(ValueRegistryImpl registry, RuntimeKey<?> key) {
return !registry.containsKey(key);
} Try / catch
try {
registry.register(key, value);
} catch (IllegalArgumentException e) {
if (e.getMessage().startsWith("Key already registered")) {
log.debugf("Key %s already registered; keeping existing value", key.key());
} else { throw e; }
} Prevention
- Check containsKey before registering
- Give each registrar/extension a unique key namespace
- Use a singleton registrar to centralize all registrations
When it happens
Trigger: Calling register()/registerInfo() twice with the same RuntimeKey, e.g. two build steps or two extension processors registering the same key, or an app restarted registration logic within one runtime instance.
Common situations: Duplicate registration from two versions of an extension on the classpath; test code re-running setup without a fresh registry; accidental copy-paste of a key constant.
Related errors
- Value cannot be null
- Name cannot start with '/':${name}
- Predicate already set
- Location already set
- The unnamed module cannot be opened to other modules
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/958783ad49dfd2a8.
Report an issue: GitHub.