eclipse-vertx/vert.x · error · IllegalArgumentException
Invalid key index: ${index}
Error message
Invalid key index: ${index} What it means
ContextBase.getLocal looks up a thread-local-style value via a ContextLocal key. Each key has a preassigned index; if the key's index exceeds the context's locals array (i.e. the key was never registered on this context type), IllegalArgumentException('Invalid key index: N') is thrown.
Source
Thrown at vertx-core/src/main/java/io/vertx/core/impl/ContextBase.java:57
VertxImpl vertx = owner();
vertx.endDispatch(previous);
}
public final <T> T getLocal(ContextLocal<T> key, AccessMode accessMode) {
ContextLocalImpl<T> internalKey = (ContextLocalImpl<T>) key;
int index = internalKey.index;
if (index >= locals.length) {
throw new IllegalArgumentException();
}
Object res = accessMode.get(locals, index);
return (T) res;
}
public final <T> T getLocal(ContextLocal<T> key, AccessMode accessMode, Supplier<? extends T> initialValueSupplier) {
ContextLocalImpl<T> internalKey = (ContextLocalImpl<T>) key;
int index = internalKey.index;
if (index >= locals.length) {
throw new IllegalArgumentException("Invalid key index: " + index);
}
Object res = accessMode.getOrCreate(locals, index, (Supplier<Object>) initialValueSupplier);
return (T) res;
}
public final <T> void putLocal(ContextLocal<T> key, AccessMode accessMode, T value) {
ContextLocalImpl<T> internalKey = (ContextLocalImpl<T>) key;
int index = internalKey.index;
if (index >= locals.length) {
throw new IllegalArgumentException();
}
accessMode.put(locals, index, value);
}
@Override
public final boolean inThread() {
return executor().inThread();
}View on GitHub (pinned to fb308bd8c3)
Solutions
- Declare the ContextLocal via ContextLocal.registerLocal(...) before any context uses it, on the same Vert.x instance
- Ensure the same key instance/registry is used for get and put — do not rebuild keys per call
- Check for multiple Vert.x instances or classloaders duplicating key registration
Example fix
// before
ContextLocal<MyState> KEY = ContextLocal.of("myKey"); // unregistered
ctx.getLocal(KEY);
// after
static final ContextLocal<MyState> KEY = ContextLocal.registerLocal(MyState::new);
ctx.getLocal(KEY); Defensive patterns
Strategy: try-catch
Validate before calling
// ensure key registered once, statically static final ContextLocal<MyState> KEY = ContextLocal.registerLocal(MyState::new);
Try / catch
try { return ctx.getLocal(KEY); } catch (IllegalArgumentException e) { throw new IllegalStateException("ContextLocal key not registered for this context", e); } Prevention
- Register ContextLocal keys statically, once per class, via ContextLocal.registerLocal
- Never create ad-hoc ContextLocal instances at call sites
- Avoid sharing keys across multiple Vert.x instances/classloaders
When it happens
Trigger: Calling vertx.getOrCreateContext().getLocal(someContextLocal) / putLocal with a ContextLocal that was not registered for that context (wrong context local registry), or using a key created against a different Vert.x/context configuration.
Common situations: Sharing a ContextLocal between different Vert.x instances; registering context locals after contexts were created; misuse across Vert.x versions where key indexes are assigned differently.
Understand the failure class
Background: "must be a positive integer", "cannot be empty", "invalid argument": how invalid-argument errors work across open-source libraries — this error's family across 33 libraries.
Related errors
- Can't register a system codec
- Cannot open file for neither reading nor writing
- Invalid setting
- maxWebSockets must be > 0 or -1 (disabled)
- code: <statusCode> (expected: 0+)
AI-assisted analysis of eclipse-vertx/vert.x@fb308bd8c3 (2026-09-06).
Data as JSON: /api/errors/7c83f3cee35e948c.
Report an issue: GitHub.