{"record":{"id":"0422d93bbc03f45d","repo":"eclipse-vertx/vert.x","slug":"expecting-the-current-parser-token-to-be-the-start","errorCode":null,"errorMessage":"Expecting the current parser token to be the start of an object","messagePattern":"Expecting the current parser token to be the start of an object","errorType":"exception","errorClass":"DecodeException","httpStatus":null,"severity":"error","filePath":"vertx-core/src/main/java/io/vertx/core/json/jackson/JacksonCodec.java","lineNumber":322,"sourceCode":"        return Boolean.TRUE;\n      case JsonTokenId.ID_FALSE:\n         return Boolean.FALSE;\n      case JsonTokenId.ID_NULL:\n        return null;\n      default:\n        throw new DecodeException(\"Unexpected token\"/*, parser.getCurrentLocation()*/);\n    }\n  }\n\n  /**\n   * Parse a JSON object given the {@code parser}, the parser current token must be {@link JsonTokenId#ID_START_OBJECT}\n   *\n   * @param parser the parser\n   * @return the parsed object\n   */\n  public static Map<String, Object> parseObject(JsonParser parser) throws IOException {\n    if (parser.currentTokenId() != JsonTokenId.ID_START_OBJECT) {\n      throw new DecodeException(\"Expecting the current parser token to be the start of an object\");\n    }\n    return internalParseObject(parser);\n  }\n\n  private static Map<String, Object> internalParseObject(JsonParser parser) throws IOException {\n    String key1 = parser.nextFieldName();\n    if (key1 == null) {\n      return new LinkedHashMap<>(2);\n    }\n    parser.nextToken();\n    Object value1 = parseValue(parser);\n    String key2 = parser.nextFieldName();\n    if (key2 == null) {\n      LinkedHashMap<String, Object> obj = new LinkedHashMap<>(2);\n      obj.put(key1, value1);\n      return obj;\n    }\n    parser.nextToken();","sourceCodeStart":304,"sourceCodeEnd":340,"githubUrl":"https://github.com/eclipse-vertx/vert.x/blob/fb308bd8c3f12c79f4ae89bef67fadf6c80d036e/vertx-core/src/main/java/io/vertx/core/json/jackson/JacksonCodec.java#L304-L340","documentation":"JacksonCodec.parseObject(JsonParser) requires the parser's current token to be START_OBJECT. When it is not, it throws DecodeException(\"Expecting the current parser token to be the start of an object\"). This guards callers who explicitly ask to parse an object but position the parser at a different token (e.g. the start of an array or a scalar).","triggerScenarios":"Calling JacksonCodec.parseObject(parser) (or fromParser targeting a Map type) when the parser's current token is ID_START_ARRAY, a scalar value, or null/no token — i.e. the input is a JSON array, string, number, boolean, null, or empty.","commonSituations":"Decoding an API response that is a top-level JSON array (e.g. a list of items) into a Map/JsonObject; decoding an empty body; a producer changed its response shape from object to array; cursor mispositioning after manual parser use.","solutions":["Check the payload's first non-whitespace character: use parseArray (or JsonDecoder for arrays) if it starts with '['","Inspect the actual response shape (curl/log it) and decode into the matching type (JsonObject vs JsonArray)","If the shape can vary, peek at the first token and branch on ID_START_OBJECT vs ID_START_ARRAY","Fix or wrap the upstream to return a top-level object if a map is required"],"exampleFix":"// before\nJsonObject obj = (JsonObject) Json.decodeValue(body); // body is '[...]'\n// after\nObject parsed = Json.decodeValue(body);\nif (parsed instanceof JsonArray arr) {\n  processList(arr);\n} else if (parsed instanceof JsonObject obj) {\n  processObject(obj);\n} else {\n  throw new IllegalStateException(\"Unexpected JSON shape\");\n}","handlingStrategy":"type-guard","validationCode":"// Java\npublic static boolean isJsonObjectPayload(String s) {\n  return s != null && s.stripLeading().startsWith(\"{\");\n}","typeGuard":"public static Object decodeFlexible(String s) {\n  String t = s == null ? \"\" : s.stripLeading();\n  if (t.startsWith(\"{\")) return new io.vertx.core.json.JsonObject(s);\n  if (t.startsWith(\"{\".substring(0,0) + \"[\")) return new io.vertx.core.json.JsonArray(s);\n  return null; // scalar or invalid\n}","tryCatchPattern":"try {\n  return JacksonCodec.parseObject(parser);\n} catch (DecodeException e) {\n  if (e.getMessage().contains(\"start of an object\")) {\n    // parser sits on an array/scalar — handle alternative shape\n    if (parser.currentTokenId() == com.fasterxml.jackson.core.JsonTokenId.ID_START_ARRAY) {\n      return JacksonCodec.parseArray(parser);\n    }\n  }\n  throw e;\n}","preventionTips":["Inspect the first non-whitespace character to choose object vs array decoding","Pin API contracts: expect a top-level object and validate upstream changes","Decode with Json.decodeValue into Object and instanceof-check the result","Add contract tests against real response shapes"],"tags":["json","decoding","type-mismatch","jackson"],"backgroundTag":"shape-mismatch","analyzedSha":"fb308bd8c3f12c79f4ae89bef67fadf6c80d036e","analyzedAt":"2026-09-06T11:37:12.241Z","contentChangedAt":"2026-09-06T11:37:12.241Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}