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

  1. Declare the ContextLocal via ContextLocal.registerLocal(...) before any context uses it, on the same Vert.x instance
  2. Ensure the same key instance/registry is used for get and put — do not rebuild keys per call
  3. 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

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


AI-assisted analysis of eclipse-vertx/vert.x@fb308bd8c3 (2026-09-06). Data as JSON: /api/errors/7c83f3cee35e948c. Report an issue: GitHub.