JSON troubleshooting
Jackson: Unrecognized token / Unexpected character ('<' (code 60))
Diagnose Jackson JsonParseException messages such as Unrecognized token 'abc' and Unexpected character ('<' (code 60)), including Spring JSON parse error responses.
What the error means
Jackson's parser reached a place where a JSON value must start and found something else. If the text there looks like a word, Jackson reports Unrecognized token and quotes the word. Otherwise it reports Unexpected character with the character and its code point. The input is usually not JSON (an HTML page, a plain-text error or a form-encoded body), or a value is written without quotes, or it uses a literal from another language such as undefined, True or None. Spring shows the same text after JSON parse error: in a 400 response.
Exact messages by runtime
Messages depend on the input and runtime version. Node and Python rows were reproduced locally. Other rows cite official documentation or source. Rows marked as fragments or templates preserve the source wording and are not complete exception transcripts. Browsers and libraries may append location details.
| Runtime | Message | Input and evidence |
|---|---|---|
| Java / Jackson 2.10+ and 3.x | Unrecognized token 'undefined': was expecting (JSON String, Number, Array, Object or token 'null', 'true' or 'false') | {"id": undefined}Source-derived from the Jackson 2.22 template and value list; location suffix omitted |
| Java / Jackson 2.10+ and 3.x, symbol | Unexpected character ('<' (code 60)): expected a valid value (JSON String, Number, Array, Object or token 'null', 'true' or 'false') | <!DOCTYPE html>Source-derived from Jackson 2.22; location suffix omitted |
| Java / Jackson 2.9 and earlier | Unrecognized token 'undefined': was expecting ('true', 'false' or 'null') | {"id": undefined}Source-derived from the Jackson 2.9.10 template |
| Java / Jackson 2.9, symbol | Unexpected character ('<' (code 60)): expected a valid value (number, String, array, object, 'true', 'false' or 'null') | <!DOCTYPE html>Source-derived from the Jackson 2.9.10 template |
| Java / Jackson, NaN | Non-standard token 'NaN': enable `JsonReadFeature.ALLOW_NON_NUMERIC_NUMBERS` to allow | {"score": NaN}Official Jackson 2.22 source text |
| Spring MVC | JSON parse error: Unrecognized token 'undefined': was expecting (JSON String, Number, Array, Object or token 'null', 'true' or 'false') | A @RequestBody with the same bodySpring Framework 7.0.9 source: JSON parse error: plus the original Jackson message |
Causes you can reproduce
The body is HTML or plain text
An error page, a login redirect or a proxy page starts with <, which Jackson reports as Unexpected character. A plain-text message starts with a word and becomes Unrecognized token.
ObjectMapper mapper = new ObjectMapper();
mapper.readTree("<!DOCTYPE html>");
// Unexpected character ('<' (code 60)): expected a valid value ...
mapper.readTree("Service Unavailable");
// Unrecognized token 'Service': was expecting ...A value has no quotes or comes from another language
JSON strings need double quotes, and the only literals are true, false and null in lower case. Python True and None, JavaScript undefined and bare words all fail.
mapper.readTree("{\"status\": active}");
// Unrecognized token 'active': was expecting ...
mapper.readTree("{\"ok\": True}");
// Unrecognized token 'True': was expecting ...A form-encoded body is sent as JSON
A client that sends name=Ada&age=36 with Content-Type: application/json makes Jackson read the first word as a token.
mapper.readTree("name=Ada&age=36");
// Unrecognized token 'name': was expecting ...How to fix it
- Capture the exact text Jackson received. The quoted token or character is the first thing that is not JSON, and the location suffix gives its line and column.
- For HTML or plain text, fix the URL, authentication or upstream error, and check the HTTP status and Content-Type before calling readValue.
- For unquoted values or literals such as True, None, NaN or undefined, fix the producer so it writes standard JSON.
- Enable lenient JsonReadFeature options such as ALLOW_SINGLE_QUOTES or ALLOW_NON_NUMERIC_NUMBERS only when you deliberately accept that non-standard input.
Check the HTTP response before parsing
Uses java.net.http (Java 11 and later) inside a method that declares throws Exception. In Jackson 3, ObjectMapper and JsonNode are in tools.jackson.databind.
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder(URI.create("https://example.com/api/items"))
.header("Accept", "application/json")
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
String type = response.headers().firstValue("Content-Type").orElse("");
if (response.statusCode() / 100 != 2 || !type.startsWith("application/json")) {
String body = response.body();
throw new IllegalStateException("Expected JSON, got " + response.statusCode() + " " + type
+ ": " + body.substring(0, Math.min(body.length(), 200)));
}
JsonNode data = new ObjectMapper().readTree(response.body());Find the exact position with Tool Kumar
- Copy the exact input text, including its original whitespace. For HTTP failures, copy the raw response body.
- Open the Tool Kumar JSON validator and paste the text. The document stays in your browser.
- Read the line and column in the error or fixable-issue banner. For an invalid document, select Go to error to move the caret to that location.
- Inspect the preceding token as well as the marked character. A parser marks where it discovered the problem; the missing quote, separator or value can start earlier.
Python character offsets are zero-based, while its displayed lines and columns are one-based. V8 string positions count UTF-16 code units; Go offsets count bytes read. Unicode text can make these offsets differ. Use the original text and its line/column context rather than copying an offset between runtimes.
Tool Kumar can classify some input as fixable loose JSON. Review a proposed change before using the JSON repair tool, then validate the result against your API contract. For empty input, inspect the producer or response because there is no character to select.
Frequently asked questions
What is the difference between Unrecognized token and Unexpected character?
Jackson reports Unrecognized token when the unexpected text starts like a Java identifier, and quotes the whole word. Anything else, such as <, a single quote or another symbol, is reported as Unexpected character with its code point.
Why does Spring return 400 with JSON parse error?
Spring wraps the Jackson exception in HttpMessageNotReadableException and puts JSON parse error: before the original message. The request body is not valid JSON, so log it or reproduce the request to see the token.
Which exception class is it?
Jackson 2 throws com.fasterxml.jackson.core.JsonParseException. Jackson 3 throws tools.jackson.core.exc.StreamReadException. The message text is the same.
Can Jackson accept single quotes or NaN?
Yes, with JsonReadFeature.ALLOW_SINGLE_QUOTES, ALLOW_UNQUOTED_FIELD_NAMES or ALLOW_NON_NUMERIC_NUMBERS enabled on a JsonMapper builder. Use them only when your input contract allows that syntax, because other parsers will still reject it.
Related errors and tools
- Jackson: Cannot deserialize value of type from Array or Object value
- Jackson: Unrecognized field, not marked as ignorable
- Unexpected token '<' / DOCTYPE is not valid JSON
- Expecting property name enclosed in double quotes
- All JSON error guides
- JSON syntax reference
- Generate Java records with Jackson annotations from valid JSON
Standards and diagnostic sources
RFC 8259 and ECMA-404 define JSON syntax. Diagnostic wording belongs to the parser. The table links each cited message to its source.