Expected BEGIN_OBJECT but was STRING
com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING at line 3 column 16 path $.customer
What it means
Gson wanted a JSON object and found something else. Read the end of the message. column 1 path $ means the body is not JSON. A path like $.customer means one field has the wrong type in your class.
Last verified on Gson 2.13.
This JSON is valid. The problem is on the Java side, so a JSON validator would say it is fine.
- Usually
- line 1 column 1 path $: the body is not JSONbut was STRING at column 2 path $: the body is a JSON stringpath $.customer: one field has the wrong typeBEGIN_ARRAY: a list where the class wants one object, or the reverseIt happens in Retrofit too
- Fix
- Read the column and the path, then fix what they point at.
The fix
Read the column and the path, then fix what they point at. If the body is not JSON, log it and find out why you got it. If a field has the wrong type, change the field in your class, as in the fixed code.
{
"id": 1,
"customer": "Ada"
}public class Order {
public long id;
public Customer customer;
}
public class Customer {
public String name;
}
Order order = gson.fromJson(json, Order.class);5 lines change.
public class Order {
public long id;
public String customer;
}
Order order = gson.fromJson(json, Order.class);How the message appears
The first line is the example on this page. The rest are the same message for other bodies: an HTML page or plain text, a JSON string, a list where the class wants one object, an object where it wants a list, and the reverse of this page, an object in a field that is a string. Every one of them is followed by the link on the last line.
- com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING at line 3 column 16 path $.customer
- com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING at line 1 column 1 path $
- com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING at line 1 column 2 path $
- com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was BEGIN_ARRAY at line 1 column 2 path $
- com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 1 column 2 path $
- com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected a string but was BEGIN_OBJECT at line 1 column 22 path $.status
- See https://github.com/google/gson/blob/main/Troubleshooting.md#unexpected-json-structure
What causes it
line 1 column 1 path $: the body is not JSON
Column 1 and path
$mean the first character of the body is not JSON. It is an HTML error page or a plain-text error such aserror: upstream timeout. Gson reads leniently by default, so it takes that text as a string and says your class needs an object. A strict Gson reader calls the same kind of text malformed JSON instead. Log the body and look at the status code.but was STRING at column 2 path $: the body is a JSON string
The whole body is one JSON string, and the object you wanted is inside it with every quote escaped. That means the JSON was encoded twice. The sender turned an object into a string and then put the string through JSON again. Fix the sender so it sends the object.
path $.customer: one field has the wrong type
A name after the
$is the field. In this example the JSON has"customer": "Ada", a string, and your class haspublic Customer customer, so Gson wants an object there. Change the field toString, as in the fixed code, or get the sender to send an object. The reverse givesExpected a string but was BEGIN_OBJECTwith the path of the field.BEGIN_ARRAY: a list where the class wants one object, or the reverse
If the JSON starts with
[and you asked forOrder.class, Gson saysExpected BEGIN_OBJECT but was BEGIN_ARRAY. If it starts with{and you asked for aList<Order>, it saysExpected BEGIN_ARRAY but was BEGIN_OBJECT. Look at the first character of the body and at the type you asked for.It happens in Retrofit too
Retrofit with the Gson converter hands the response body to Gson, so a Retrofit call can throw this as well. The cause is the same. Log the raw body and compare it with your class. Retrofit was not tested here.
Worth knowing
NoteJackson words a list read into one object as Cannot deserialize value of type. See Cannot deserialize from Array value.
NoteWhen the text is not JSON at all and you read it as a plain Object, Gson says MalformedJsonException instead. See MalformedJsonException.