HttpMessageNotReadableException: JSON parse error

ErrorJava

org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Unexpected character ('"' (code 34)): was expecting comma to separate Object entries

Where JSON.parse stops

  "id": 7
  "status": "shipped"
}

What it means

Spring adds JSON parse error: in front of the message Jackson threw, so the useful part is everything after the colon. Find that part in the list below and fix what it points at, either the JSON or your Java class.

Last verified on Jackson 2.21 and 3.1; Spring 6.2 and 7.0.

The validator opens with the error marked. Examples travel in the URL fragment, which browsers never send to a server.

Express Lint lays broken JSON out by bracket depth and marks the line where it stops. It changes only spaces and line breaks outside strings. Strings in either quote stay as written. If the quotes do not pair up, it leaves your text as it is. Ctrl+Z undoes it. See how it works.

Usually
Unrecognized token: a word where a value should beUnexpected character: a character in the wrong placeCannot deserialize: valid JSON, wrong Java typeType definition error: Jackson cannot build your classNo content to map: the body is empty
Fix
Read the text after JSON parse error:.

The fix

Read the text after JSON parse error:. That is Jackson's message, and it tells you what is wrong. In the example here a comma is missing after 7, so add it. If the message is about a type (Cannot deserialize, Cannot construct), the JSON is fine and the fix is in your Java class.

broken.jsonFails to parse
{
  "id": 7
  "status": "shipped"
}
JSON.parse stops at line 3, column 3.

Line 2: add ,.

fixed.jsonParses
{
  "id": 7,
  "status": "shipped"
}
JSON.parse reads it.

How the message appears

First the Spring line, which is what shows up in your log. Spring 6.2 and 7.0 print the same thing. Then what Jackson 2 and Jackson 3 print for the same body, each followed by where it stopped. The last four are other errors you will see after the same prefix. Note the Type definition error one: it is a different exception, HttpMessageConversionException.

Console
  • org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Unexpected character ('"' (code 34)): was expecting comma to separate Object entries
  • com.fasterxml.jackson.core.JsonParseException: Unexpected character ('"' (code 34)): was expecting comma to separate Object entries
  • at [Source: REDACTED (`StreamReadFeature.INCLUDE_SOURCE_IN_LOCATION` disabled); line: 3, column: 3]
  • tools.jackson.core.exc.StreamReadException: Unexpected character ('"' (code 34)): was expecting comma to separate Object entries
  • at [Source: REDACTED (`StreamReadFeature.INCLUDE_SOURCE_IN_LOCATION` disabled); byte offset: #UNKNOWN]
  • org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Unrecognized token 'ok': was expecting (JSON String, Number, Array, Object or token 'null', 'true' or 'false')
  • org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot deserialize value of type `com.example.Order` from Array value (token `JsonToken.START_ARRAY`)
  • org.springframework.http.converter.HttpMessageConversionException: Type definition error: [simple type, class com.example.Order]
  • org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: No content to map due to end-of-input

What causes it

  1. Unrecognized token: a word where a value should be

    Jackson found letters where a value should be, like ok without quotes. JSON only allows true, false and null without quotes. See Unrecognized token.

  2. Unexpected character: a character in the wrong place

    This page's example is one. The comma after 7 is missing, so Jackson hits the " of the next key and says it expected a comma. Trailing commas, single quotes and HTML pages give the same message with a different character code. See Unexpected character.

  3. Cannot deserialize: valid JSON, wrong Java type

    The JSON parsed fine. It just does not fit your class. from Array value means a list came in and your class expects one object. See Cannot deserialize from Array value. from String means Jackson could not turn some text into a date or a number. See Cannot deserialize from String.

  4. Type definition error: Jackson cannot build your class

    This one looks different: HttpMessageConversionException: Type definition error: [simple type, class com.example.Order]. It names the class and not the reason. Usually Jackson has no constructor it can use, or the type is abstract. With a single-argument constructor you get JSON parse error: Cannot construct instance of instead. Both are on Cannot construct instance.

  5. No content to map: the body is empty

    Jackson got nothing to read. See No content to map.

Worth knowing

NoteSpring's message does not say where in the body the problem is. Jackson 2's own message ends with an at [Source: ...] line that gives the line and column. Spring leaves it out. For a syntax error (Unrecognized token, Unexpected character), paste the body into the validator to find the spot.

NoteTwo errors may never show up in Spring. With jackson-datatype-jsr310 on the classpath, Spring read a LocalDateTime with no error. See Java 8 date/time type not supported. Spring 6.2 and 7.0 also skip keys your class does not have. See Unrecognized field. A plain Jackson 2 ObjectMapper throws both, so they can fail in a test that creates its own mapper.

Your JSON and text are processed entirely in your browser and are never sent anywhere. To understand how the site is used we record each page view (the page, the referrer and an approximate location from your IP address) and keep it for 90 days. Nothing is stored on your device unless you choose it. Accept to also store a device identifier here and record your browser and device characteristics, which is what lets a return visit be told from a new one. Decline and nothing is sent at all. We respect Do Not Track. See our privacy policy.