XINCGer/Unity3DTraining · error · InvalidProtocolBufferException
Expected '
Error message
Expected '
What it means
When the JsonParser parses the body of an Any holding a well-known type (e.g. google.protobuf.Timestamp), it expects the JSON object to contain exactly the property named 'value' (JsonFormatter.AnyWellKnownTypeValueField) after '@type'. Any other property name is rejected with this InvalidProtocolBufferException.
Solutions
- Rename the inner property to exactly 'value' (the canonical AnyWellKnownTypeValueField).
- If you control the producer, serialize well-known types inside Any per the protobuf JSON spec: {"@type":"...","value":<encoded wkt>}.
- Verify JSON casing policy (camelCase) isn't rewriting 'value' to something else.
Example fix
// before
{"@type":"type.googleapis.com/google.protobuf.Duration","val":"5s"}
// after
{"@type":"type.googleapis.com/google.protobuf.Duration","value":"5s"} Defensive patterns
Strategy: validation
Validate before calling
// Validate Any well-known-type bodies have the canonical 'value' property
var anyObjs = Regex.Matches(json, '"@type"\\s*:\\s*"[^"]+"\\s*,\\s*"([^"]+)"');
foreach (Match m in anyObjs)
if (m.Groups[1].Value != "value") throw new Exception($"Any body must use 'value', got '{m.Groups[1].Value}'"); Try / catch
try
{
var msg = parser.Parse<T>(json);
}
catch (InvalidProtocolBufferException ex) when (ex.Message.Contains("property for well-known type Any body"))
{
// inspect/repair the offending JSON or surface a clear client-side error
} Prevention
- Use protobuf's canonical JSON serializer on the producer side (never hand-roll Any JSON)
- Use lowercase 'value' exactly, per the protobuf JSON mapping
- Add round-trip tests: serialize with the producer, deserialize with this parser
When it happens
Trigger: Parsing an Any body like {"@type":"type.googleapis.com/google.protobuf.Timestamp","value":"..."} where the second property is misspelled (e.g. 'Value', 'val') or in wrong order/casing, so the first token after @type is not a Name token equal to the canonical field name.
Common situations: Hand-crafted or third-party-generated JSON for Any-wrapped well-known types with wrong property casing or naming; serializers that don't follow the canonical Any well-known-type encoding.
Understand the failure class
Background: "cannot parse invalid wire-format data", "cannot unmarshal", "failed unmarshalling": protobuf unmarshal errors explained — this error's family across 10 libraries.
Related errors
- Expected end of JSON after object
- Expected an object
- Unexpected token type
- Multiple values specified for oneof
- Unknown field:
AI-assisted analysis of XINCGer/Unity3DTraining@016f98412e (2026-09-12).
Data as JSON: /api/errors/f2792f6f1a291a2c.
Report an issue: GitHub.
Appendix: source
Thrown at NetWorkAndResources/Socket_Protobuff/Assets/Plugins/Google.Protobuf/JsonParser.cs:554
}
var data = body.ToByteString();
// Now that we have the message data, we can pack it into an Any (the message received as a parameter).
message.Descriptor.Fields[Any.TypeUrlFieldNumber].Accessor.SetValue(message, typeUrl);
message.Descriptor.Fields[Any.ValueFieldNumber].Accessor.SetValue(message, data);
}
// Well-known types end up in a property called "value" in the JSON. As there's no longer a @type property
// in the given JSON token stream, we should *only* have tokens of start-object, name("value"), the value
// itself, and then end-object.
private void MergeWellKnownTypeAnyBody(IMessage body, JsonTokenizer tokenizer)
{
var token = tokenizer.Next(); // Definitely start-object; checked in previous method
token = tokenizer.Next();
// TODO: What about an absent Int32Value, for example?
if (token.Type != JsonToken.TokenType.Name || token.StringValue != JsonFormatter.AnyWellKnownTypeValueField)
{
throw new InvalidProtocolBufferException("Expected '" + JsonFormatter.AnyWellKnownTypeValueField + "' property for well-known type Any body");
}
Merge(body, tokenizer);
token = tokenizer.Next();
if (token.Type != JsonToken.TokenType.EndObject)
{
throw new InvalidProtocolBufferException("Expected end-object token after @type/value for well-known type");
}
}
#region Utility methods which don't depend on the state (or settings) of the parser.
private static object ParseMapKey(FieldDescriptor field, string keyText)
{
switch (field.FieldType)
{
case FieldType.Bool:
if (keyText == "true")
{
return true;View on GitHub (pinned to 016f98412e)