eclipse-vertx/vert.x · error · DecodeException

Failed to decode

Error message

Failed to decode

What it means

JacksonCodec.cast narrows a decoded value to the requested class. When the decoded value is a Map but the target class cannot accept a Map (clazz.isAssignableFrom(Map.class) is false), it throws DecodeException("Failed to decode"). This means the JSON document was an object but you asked to decode it into an incompatible type (e.g. a List or String class).

Source

Thrown at vertx-core/src/main/java21/io/vertx/core/json/jackson/v3/JacksonCodec.java:465

    } else if (json instanceof Float) {
      generator.writeNumber((Float) json);
    } else if (json instanceof Double) {
      generator.writeNumber((Double) json);
    } else if (json instanceof Byte) {
      generator.writeNumber((Byte) json);
    } else if (json instanceof BigInteger) {
      generator.writeNumber((BigInteger) json);
    } else if (json instanceof BigDecimal) {
      generator.writeNumber((BigDecimal) json);
    } else {
      generator.writeNumber(((Number) json).doubleValue());
    }
  }

  private static <T> T cast(Object o, Class<T> clazz) {
    if (o instanceof Map) {
      if (!clazz.isAssignableFrom(Map.class)) {
        throw new DecodeException("Failed to decode");
      }
      if (clazz == Object.class) {
        o = new JsonObject((Map) o);
      }
      return clazz.cast(o);
    } else if (o instanceof List) {
      if (!clazz.isAssignableFrom(List.class)) {
        throw new DecodeException("Failed to decode");
      }
      if (clazz == Object.class) {
        o = new JsonArray((List) o);
      }
      return clazz.cast(o);
    } else if (o instanceof String) {
      String str = (String) o;
      if (clazz.isEnum()) {
        o = Enum.valueOf((Class<Enum>) clazz, str);
      } else if (clazz == byte[].class) {

View on GitHub (pinned to fb308bd8c3)

Solutions

  1. Match the target type to the JSON shape: use Map.class/JsonObject.class for objects, List.class/JsonArray.class for arrays
  2. Decode without a target class (Json.decodeValue(buffer)) and convert manually, or use a POJO mapping with jackson-databind available
  3. If the payload changed shape, update the producer or adapt the consumer's expected type

Example fix

// before
Map<String,Object> m = Json.decodeValue("{\"a\":1}", List.class); // DecodeException: Failed to decode
// after
Map<String,Object> m = Json.decodeValue("{\"a\":1}", Map.class);
// or: JsonObject o = Json.decodeValue("{\"a\":1}", JsonObject.class);
Defensive patterns

Strategy: type-guard

Validate before calling

String t = input.trim();
if (!t.startsWith("{")) throw new IllegalArgumentException("payload is not a JSON object");

Type guard

static <T> boolean decodableAsMap(Class<T> c) {
  return c == Object.class || c.isAssignableFrom(Map.class);
}

Try / catch

try {
  T v = Json.decodeValue(buffer, targetType);
} catch (DecodeException e) {
  if ("Failed to decode".equals(e.getMessage())) {
    // JSON shape does not match target type; decode without target and inspect
    Object raw = Json.decodeValue(buffer);
  }
}

Prevention

When it happens

Trigger: Calling JacksonCodec.cast(mapValue, SomeClass) or decoding JSON with Json.decodeValue(buffer, X.class) where the JSON is an object and X is not Map, Object, JsonObject, or any supertype of Map — e.g. decodeValue(json, List.class) on '{"a":1}'.

Common situations: Decoding an API response that changed from an array to an object while the target type stayed List; asking for a POJO class without databind on the classpath so the raw Map cannot be mapped onto it; passing Integer.class/String.class for object-shaped JSON.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


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