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

  1. 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).
  2. Upgrade Google.Protobuf to a version where MergeStructValue's switch covers all canonical Value cases.
  3. Validate the JSON tree for Value/Struct fields: only objects, arrays, strings, numbers, and booleans are supported dispatch targets.
  4. 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

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.

Related errors


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)