XINCGer/Unity3DTraining · error · InvalidOperationException
Unexpected token type
Error message
Unexpected token type
What it means
Inside a message object, JsonParser.Merge expects alternating name/value tokens; after a value, the next token must be a field name or end-object. Any other token type indicates malformed JSON structure, so it throws InvalidOperationException (a parser invariant violation rather than a data error).
Solutions
- Validate the JSON with a standard parser (JsonDocument.Parse / JsonConvert) before feeding it to JsonParser to get a clearer error
- Fix the JSON producer so every object value is preceded by a member name
- Ensure one tokenizer per Merge call; do not interleave Next/PushBack incorrectly
- If parsing untrusted input, catch InvalidOperationException/InvalidProtocolBufferException and return a 4xx-style parse failure
Example fix
// before
string json = "{ 'a': 1, 2 }"; // missing member name
// after
string json = "{ 'a': 1, 'b': 2 }"; Defensive patterns
Strategy: try-catch
Validate before calling
// Pre-validate JSON structure with the platform parser using var doc = System.Text.Json.JsonDocument.Parse(json); // throws clearer errors on malformed JSON
Try / catch
try { return parser.Parse<T>(json); } catch (InvalidOperationException ex) when (ex.Message.StartsWith("Unexpected token type")) { log.Error("Malformed JSON structure fed to protobuf parser", ex); throw new BadRequestException("Malformed JSON", ex); } Prevention
- Validate JSON with a general-purpose parser before JsonParser
- Never hand-build JSON via string concatenation; use a serializer
- Use one tokenizer per Merge and do not misuse PushBack
When it happens
Trigger: Feeding structurally invalid JSON to JsonParser where an object member name is missing — e.g. two consecutive values without a key, an unterminated object, or a tokenizer/reader mismatch such as reusing a tokenizer across messages.
Common situations: Hand-built or template-generated JSON with missing keys; string concatenation producing malformed JSON; parser bugs or misuse of PushBack/tokenizer API in custom code paths.
Understand the failure class
Background: JSON parse error: "Unexpected token" / "not valid JSON" / "failed to parse" — what JSON parsers are really complaining about — this error's family across 45 libraries.
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- Expected end-object token after @type/value for well-known…
- Expected end of JSON after object
- Expected an object
- Multiple values specified for oneof
- Unknown field:
AI-assisted analysis of XINCGer/Unity3DTraining@016f98412e (2026-09-12).
Data as JSON: /api/errors/a9e78acb93deae24.
Report an issue: GitHub.
Appendix: source
Thrown at NetWorkAndResources/Socket_Protobuff/Assets/Plugins/Google.Protobuf/JsonParser.cs:185
{
throw new InvalidProtocolBufferException("Expected an object");
}
var descriptor = message.Descriptor;
var jsonFieldMap = descriptor.Fields.ByJsonName();
// All the oneof fields we've already accounted for - we can only see each of them once.
// The set is created lazily to avoid the overhead of creating a set for every message
// we parsed, when oneofs are relatively rare.
HashSet<OneofDescriptor> seenOneofs = null;
while (true)
{
token = tokenizer.Next();
if (token.Type == JsonToken.TokenType.EndObject)
{
return;
}
if (token.Type != JsonToken.TokenType.Name)
{
throw new InvalidOperationException("Unexpected token type " + token.Type);
}
string name = token.StringValue;
FieldDescriptor field;
if (jsonFieldMap.TryGetValue(name, out field))
{
if (field.ContainingOneof != null)
{
if (seenOneofs == null)
{
seenOneofs = new HashSet<OneofDescriptor>();
}
if (!seenOneofs.Add(field.ContainingOneof))
{
throw new InvalidProtocolBufferException("Multiple values specified for oneof " + field.ContainingOneof.Name);
}
}
MergeField(message, field, tokenizer);
}View on GitHub (pinned to 016f98412e)