XINCGer/Unity3DTraining · error · InvalidOperationException
Type registry has no descriptor for type name '
Error message
Type registry has no descriptor for type name '
What it means
Google.Protobuf's JsonParser, when parsing an google.protobuf.Any field, extracts the type name from the '@type' URL and looks it up in the parser's TypeRegistry. If the registry cannot resolve that type name, this InvalidOperationException is thrown because the parser cannot create a message template to merge the Any body into.
Solutions
- Register the missing type: JsonParser.Default.WithTypeRegistry(TypeRegistry.FromMessages(typeof(MyMessage))) and parse with that parser instance.
- Verify the @type URL's type name matches the registered message's full proto name (package.MessageName).
- If the Any payload is unknown to the client, parse the field as a raw Any (it stays unparsed) instead of requesting unpacking, and inspect TypeUrl manually.
Example fix
// before var msg = JsonParser.Default.Parse<Wrapper>(json); // after var registry = TypeRegistry.FromMessages(typeof(MyCustomMessage), typeof(AnotherMessage)); var parser = JsonParser.Default.WithTypeRegistry(registry); var msg = parser.Parse<Wrapper>(json);
Defensive patterns
Strategy: try-catch
Validate before calling
// Pre-check that every @type in the JSON is registered
var registered = TypeRegistry.FromMessages(typeof(MyMessage));
foreach (Match m in Regex.Matches(json, '"@type"\\s*:\\s*"([^"]+)"'))
{
string typeName = Any.GetTypeName(m.Groups[1].Value);
if (registered.Find(typeName) == null) throw new Exception($"Unregistered Any type: {typeName}");
} Type guard
static bool IsAnyTypeRegistered(TypeRegistry registry, string json)
{
var match = Regex.Match(json, '"@type"\\s*:\\s*"([^"]+)"');
return match.Success && registry.Find(Any.GetTypeName(match.Groups[1].Value)) != null;
} Try / catch
try
{
var msg = parser.Parse<T>(json);
}
catch (InvalidOperationException ex) when (ex.Message.StartsWith("Type registry has no descriptor"))
{
// fall back to a registry that includes the missing type, or keep Any raw
logger.LogWarning(ex, "Unknown Any type in payload");
} Prevention
- Always build parsers via JsonParser.Default.WithTypeRegistry(TypeRegistry.FromMessages(...all shared types...))
- Keep the client's type registry in sync with every message type servers may embed in Any
- Log Any.TypeUrl values in integration tests to catch registry gaps early
When it happens
Trigger: Parsing JSON containing an Any field whose @type URL names a message type that was never registered via JsonParser.WithTypeRegistry(...).With(TypeRegistry.FromMessages(...)) — e.g. parsing output from a server that used types not present or not registered on the client.
Common situations: Client/server use different .proto type sets; developer forgets to add custom message types to the TypeRegistry when deserializing Any; type name mismatch between producer and consumer (different package names).
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/e851ab6b8aa43b22.
Report an issue: GitHub.
Appendix: source
Thrown at NetWorkAndResources/Socket_Protobuff/Assets/Plugins/Google.Protobuf/JsonParser.cs:522
if (tokenizer.ObjectDepth < typeUrlObjectDepth)
{
throw new InvalidProtocolBufferException("Any message with no @type");
}
}
// Don't add the @type property or its value to the recorded token list
token = tokenizer.Next();
if (token.Type != JsonToken.TokenType.StringValue)
{
throw new InvalidProtocolBufferException("Expected string value for Any.@type");
}
string typeUrl = token.StringValue;
string typeName = Any.GetTypeName(typeUrl);
MessageDescriptor descriptor = settings.TypeRegistry.Find(typeName);
if (descriptor == null)
{
throw new InvalidOperationException("Type registry has no descriptor for type name '" + typeName + "'");
}
// Now replay the token stream we've already read and anything that remains of the object, just parsing it
// as normal. Our original tokenizer should end up at the end of the object.
var replay = JsonTokenizer.FromReplayedTokens(tokens, tokenizer);
var body = descriptor.Parser.CreateTemplate();
if (descriptor.IsWellKnownType)
{
MergeWellKnownTypeAnyBody(body, replay);
}
else
{
Merge(body, replay);
}
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);View on GitHub (pinned to 016f98412e)