{"record":{"id":"e4da922c5e096e04","repo":"eclipse-vertx/vert.x","slug":"cannot-put-null-in-key-or-value-of-async-map","errorCode":null,"errorMessage":"Cannot put null in key or value of async map","messagePattern":"Cannot put null in key or value of async map","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"vertx-core/src/main/java/io/vertx/core/shareddata/impl/SharedDataImpl.java","lineNumber":142,"sourceCode":"\n  @SuppressWarnings(\"unchecked\")\n  @Override\n  public <K, V> Future<AsyncMap<K, V>> getLocalAsyncMap(String name) {\n    LocalAsyncMapImpl<K, V> asyncMap = (LocalAsyncMapImpl<K, V>) localAsyncMaps.computeIfAbsent(name, n -> new LocalAsyncMapImpl<>(vertx));\n    ContextInternal context = vertx.getOrCreateContext();\n    return context.succeededFuture(new WrappedAsyncMap<>(asyncMap));\n  }\n\n  @Override\n  public Future<Counter> getLocalCounter(String name) {\n    Counter counter = localCounters.computeIfAbsent(name, n -> new AsynchronousCounter(vertx));\n    ContextInternal context = vertx.getOrCreateContext();\n    return context.succeededFuture(counter);\n  }\n\n  private static void checkType(Object obj) {\n    if (obj == null) {\n      throw new IllegalArgumentException(\"Cannot put null in key or value of async map\");\n    }\n    // All immutables and byte arrays are Serializable by the platform\n    if (!(obj instanceof Serializable || obj instanceof ClusterSerializable)) {\n      throw new IllegalArgumentException(\"Invalid type: \" + obj.getClass().getName() + \" to put in async map\");\n    }\n  }\n\n  public static final class WrappedAsyncMap<K, V> implements AsyncMap<K, V> {\n\n    private final AsyncMap<K, V> delegate;\n\n    WrappedAsyncMap(AsyncMap<K, V> other) {\n      this.delegate = other;\n    }\n\n    @Override\n    public Future<V> get(K k) {\n      checkType(k);","sourceCodeStart":124,"sourceCodeEnd":160,"githubUrl":"https://github.com/eclipse-vertx/vert.x/blob/fb308bd8c3f12c79f4ae89bef67fadf6c80d036e/vertx-core/src/main/java/io/vertx/core/shareddata/impl/SharedDataImpl.java#L124-L160","documentation":"SharedDataImpl.checkType rejects null keys or values before they reach an async map: async maps cannot store null entries because keys/values must be serializable and Comparable across the cluster. It throws IllegalArgumentException with this message.","triggerScenarios":"Calling put/putIfAbsent/get/replace on an AsyncMap or cluster-wide map with a null key or null value.","commonSituations":"A lookup returned null and its result was passed straight to map.put; optional config values (null when unset) used as values; deserialized JSON fields defaulting to null.","solutions":["Check key/value for null before calling any map method and handle the null case explicitly.","Provide a non-null default or sentinel value instead of storing null.","Fix the upstream producer so the value is never null (Objects.requireNonNull at creation)."],"exampleFix":"// before\nString val = config.getString(\"opt\");\nmap.put(\"k\", val); // NPE risk / IllegalArgumentException when val == null\n// after\nString val = config.getString(\"opt\");\nif (val != null) map.put(\"k\", val);","handlingStrategy":"validation","validationCode":"if (key == null || value == null) {\n  throw new IllegalArgumentException(\"async map key/value must be non-null\");\n}","typeGuard":"static <V> java.util.Optional<V> nonNullValue(V v) { return java.util.Optional.ofNullable(v); }","tryCatchPattern":"try {\n  map.put(key, value);\n} catch (IllegalArgumentException e) {\n  if (e.getMessage().contains(\"Cannot put null\")) {\n    map.put(key, defaultValue);\n  } else throw e;\n}","preventionTips":["Wrap nullable producer results in Optional and only put when present.","Use Objects.requireNonNull early where values are created, not at storage time.","Never store null as a tombstone; use remove(key) instead."],"tags":["shared-data","async-map","null-check","illegal-argument"],"backgroundTag":"null-argument","analyzedSha":"fb308bd8c3f12c79f4ae89bef67fadf6c80d036e","analyzedAt":"2026-09-06T11:37:12.241Z","contentChangedAt":"2026-09-06T11:37:12.241Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}