eclipse-vertx/vert.x · error · DecodeException

Expecting the current parser token to be the start of an arr

Error message

Expecting the current parser token to be the start of an array

What it means

JacksonCodec.parseArray(JsonParser) requires the parser's current token to be START_ARRAY. When it is not, it throws DecodeException("Expecting the current parser token to be the start of an array"). This guards callers who explicitly ask to parse an array but position the parser at another token (e.g. an object or a scalar).

Source

Thrown at vertx-core/src/main/java/io/vertx/core/json/jackson/JacksonCodec.java:370

    obj.put(key2, value2);
    do {
      parser.nextToken();
      Object value = parseValue(parser);
      obj.put(key, value);
      key = parser.nextFieldName();
    } while (key != null);
    return obj;
  }

  /**
   * Parse a JSON array given the {@code parser}, the parser current token must be {@link JsonTokenId#ID_START_ARRAY}
   *
   * @param parser the parser
   * @return the parsed array
   */
  public static List<Object> parseArray(JsonParser parser) throws IOException {
    if (parser.currentTokenId() != JsonTokenId.ID_START_ARRAY) {
      throw new DecodeException("Expecting the current parser token to be the start of an array");
    }
    return internalParseArray(parser);
  }

  private static List<Object> internalParseArray(JsonParser parser) throws IOException {
    List<Object> array = new ArrayList<>();
    while (true) {
      parser.nextToken();
      int tokenId = parser.currentTokenId();
      if (tokenId == JsonTokenId.ID_FIELD_NAME) {
        throw new UnsupportedOperationException();
      } else if (tokenId == JsonTokenId.ID_END_ARRAY) {
        return array;
      }
      Object value = parseValue(parser);
      array.add(value);
    }
  }

View on GitHub (pinned to fb308bd8c3)

Solutions

  1. Check the payload's first non-whitespace character: use parseObject (or decode to JsonObject) if it starts with '{'
  2. Inspect the actual response shape and decode into the matching type (JsonArray vs JsonObject)
  3. If the shape can vary, peek at the first token and branch on ID_START_ARRAY vs ID_START_OBJECT
  4. Handle the single-object case by wrapping it in a list before/after decoding if a list is required

Example fix

// before
JsonArray arr = (JsonArray) Json.decodeValue(body); // body is '{...}'
// after
Object parsed = Json.decodeValue(body);
JsonArray arr = parsed instanceof JsonArray a ? a
    : new JsonArray(java.util.List.of(parsed));
processList(arr);
Defensive patterns

Strategy: type-guard

Validate before calling

// Java
public static boolean isJsonArrayPayload(String s) {
  return s != null && s.stripLeading().startsWith("[");
}

Type guard

public static Object decodeFlexible(String s) {
  String t = s == null ? "" : s.stripLeading();
  if (t.startsWith("[")) return new io.vertx.core.json.JsonArray(s);
  if (t.startsWith("{")) return new io.vertx.core.json.JsonObject(s);
  return null; // scalar or invalid
}

Try / catch

try {
  return JacksonCodec.parseArray(parser);
} catch (DecodeException e) {
  if (e.getMessage().contains("start of an array")) {
    // parser sits on an object/scalar — handle alternative shape
    if (parser.currentTokenId() == com.fasterxml.jackson.core.JsonTokenId.ID_START_OBJECT) {
      return java.util.List.of(JacksonCodec.parseObject(parser));
    }
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling JacksonCodec.parseArray(parser) (or fromParser targeting a List type) when the parser's current token is ID_START_OBJECT, a scalar value, or null/no token — i.e. the input is a JSON object, string, number, boolean, null, or empty.

Common situations: Decoding a top-level JSON object into a List/JsonArray; decoding an empty response body; a producer changed its response shape from array to single object; wrapping a scalar endpoint result that used to be an array.

Related errors


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