XINCGer/Unity3DTraining · error · InvalidOperationException
Unexpected token type:
Error message
Unexpected token type:
What it means
MergeStructValue dispatches on the first JSON token to parse a google.protobuf.Value (Value message): objects, arrays, strings, numbers, and booleans are all handled; any other first-token type falls through to this InvalidOperationException. It represents an internal dispatch gap in the Value parser.
Solutions
- Avoid null as the JSON value for google.protobuf.Value fields; use the Value null_value variant represented per canonical mapping (this dispatch path usually catches a routing gap).
- Upgrade Google.Protobuf to a version where MergeStructValue's switch covers all canonical Value cases.
- Validate the JSON tree for Value/Struct fields: only objects, arrays, strings, numbers, and booleans are supported dispatch targets.
- Catch InvalidOperationException and log the firstToken.Type from the message to identify the unsupported token.
Example fix
// before
{"payload": null} // payload is google.protobuf.Value
// after: use the null variant explicitly if the version requires it
{"payload": {"nullValue": "NULL_VALUE"}} Defensive patterns
Strategy: validation
Validate before calling
// google.protobuf.Value accepts object|array|string|number|boolean only
function isValidValuePayload(v) {
return v === 'string' || ['object','array','string','number','boolean'].includes(v) === false ? false : true;
}
// practical check: reject null before it reaches Value dispatch
if (payload.payloadField === null) throw new Error('null not supported for Value dispatch in this parser version'); Type guard
function isSupportedValueToken(v) { return v !== null && v !== undefined; } Try / catch
try { var msg = JsonParser.Default.Parse<T>(json); }
catch (InvalidOperationException ex) when (ex.Message.StartsWith("Unexpected token type")) { /* log token type; fall back to preprocessed parse */ } Prevention
- Keep Google.Protobuf up to date so Value parsing covers all canonical cases
- Avoid null JSON values for Value/Struct fields; use the null_value variant mapping
- Fuzz-test Struct/Value payloads against the parser in CI
When it happens
Trigger: Parsing a google.protobuf.Value/Struct payload whose first token is none of StartObject/StartArray/StringValue/Number/true/false — typically a Null token (null JSON value) or a tokenizer-emitted Name token reaching MergeStructValue directly.
Common situations: JSON with a literal null assigned to a Value-typed field reaching this dispatch (null handling is unimplemented elsewhere too); custom tokenizers producing unexpected token types; internal bug reports from deep nested Struct payloads.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- Expected object value for Struct
- SkipLastField cannot be called at the end of a stream
- SpaceLeft can only be called on CodedOutputStreams that are…
- Struct fields cannot have an empty key or a null value.
- Value message must contain a value for the oneof.
AI-assisted analysis of XINCGer/Unity3DTraining@016f98412e (2026-09-12).
Data as JSON: /api/errors/f49e4848bd520c81.
Report an issue: GitHub.
Appendix: source
Thrown at NetWorkAndResources/Socket_Protobuff/Assets/Plugins/Google.Protobuf/JsonParser.cs:465
{
var field = fields[Value.StructValueFieldNumber];
var structMessage = NewMessageForField(field);
tokenizer.PushBack(firstToken);
Merge(structMessage, tokenizer);
field.Accessor.SetValue(message, structMessage);
return;
}
case JsonToken.TokenType.StartArray:
{
var field = fields[Value.ListValueFieldNumber];
var list = NewMessageForField(field);
tokenizer.PushBack(firstToken);
Merge(list, tokenizer);
field.Accessor.SetValue(message, list);
return;
}
default:
throw new InvalidOperationException("Unexpected token type: " + firstToken.Type);
}
}
private void MergeStruct(IMessage message, JsonTokenizer tokenizer)
{
var token = tokenizer.Next();
if (token.Type != JsonToken.TokenType.StartObject)
{
throw new InvalidProtocolBufferException("Expected object value for Struct");
}
tokenizer.PushBack(token);
var field = message.Descriptor.Fields[Struct.FieldsFieldNumber];
MergeMapField(message, field, tokenizer);
}
private void MergeAny(IMessage message, JsonTokenizer tokenizer)
{View on GitHub (pinned to 016f98412e)