eclipse-vertx/vert.x · error · IllegalArgumentException

Invalid type: ${obj.getClass().getName()} to put in async ma

Error message

Invalid type: ${obj.getClass().getName()} to put in async map

What it means

SharedDataImpl.checkType validates that keys/values put into an async map are either Serializable or ClusterSerializable so they can be marshalled across the cluster. Otherwise it throws IllegalArgumentException listing the offending class name.

Source

Thrown at vertx-core/src/main/java/io/vertx/core/shareddata/impl/SharedDataImpl.java:146

    LocalAsyncMapImpl<K, V> asyncMap = (LocalAsyncMapImpl<K, V>) localAsyncMaps.computeIfAbsent(name, n -> new LocalAsyncMapImpl<>(vertx));
    ContextInternal context = vertx.getOrCreateContext();
    return context.succeededFuture(new WrappedAsyncMap<>(asyncMap));
  }

  @Override
  public Future<Counter> getLocalCounter(String name) {
    Counter counter = localCounters.computeIfAbsent(name, n -> new AsynchronousCounter(vertx));
    ContextInternal context = vertx.getOrCreateContext();
    return context.succeededFuture(counter);
  }

  private static void checkType(Object obj) {
    if (obj == null) {
      throw new IllegalArgumentException("Cannot put null in key or value of async map");
    }
    // All immutables and byte arrays are Serializable by the platform
    if (!(obj instanceof Serializable || obj instanceof ClusterSerializable)) {
      throw new IllegalArgumentException("Invalid type: " + obj.getClass().getName() + " to put in async map");
    }
  }

  public static final class WrappedAsyncMap<K, V> implements AsyncMap<K, V> {

    private final AsyncMap<K, V> delegate;

    WrappedAsyncMap(AsyncMap<K, V> other) {
      this.delegate = other;
    }

    @Override
    public Future<V> get(K k) {
      checkType(k);
      return delegate.get(k);
    }

    @Override

View on GitHub (pinned to fb308bd8c3)

Solutions

  1. Make the class implement Serializable (or ClusterSerializable for efficient binary encoding).
  2. Convert to a supported type before storing: JsonObject, Buffer, String, byte[], boxed primitives.
  3. Store a serializable DTO mapped from the domain object and convert back on read.

Example fix

// before
map.put("user", new User("a")); // User not serializable -> IllegalArgumentException
// after
map.put("user", JsonObject.mapFrom(new User("a")));
Defensive patterns

Strategy: type-guard

Validate before calling

static boolean isMapCompatible(Object o) {
  return o instanceof java.io.Serializable || o instanceof io.vertx.core.cluster.ClusterSerializable;
}
if (!isMapCompatible(key) || !isMapCompatible(value)) throw new IllegalArgumentException("type not storable in async map");

Type guard

static boolean isMapCompatible(Object o) {
  return o instanceof java.io.Serializable || o instanceof io.vertx.core.cluster.ClusterSerializable;
}

Try / catch

try {
  map.put(key, value);
} catch (IllegalArgumentException e) {
  if (e.getMessage().startsWith("Invalid type")) {
    map.put(key, JsonObject.mapFrom(value));
  } else throw e;
}

Prevention

When it happens

Trigger: Calling put/putIfAbsent/replace on an AsyncMap (including getClusterWideMap / getAsyncMap results) with a non-null object whose class implements neither Serializable nor ClusterSerializable.

Common situations: Storing POJOs, third-party types (e.g. DateTime variants, streams, connections) into cluster maps; refactors dropped implements Serializable; type mismatch between dev (local map, lenient) and prod (cluster map, strict).

Understand the failure class

Background: "is not a compatible type" / "cannot merge" errors: when a value's type doesn't match what the library requires — this error's family across 65 libraries.

Related errors


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