XINCGer/Unity3DTraining · error · DescriptorValidationException
Field with message or enum type missing type_name.
Error message
Field with message or enum type missing type_name.
What it means
During descriptor cross-linking, Google.Protobuf validates every FieldDescriptorProto. If a field's type resolves to FieldType.Message or FieldType.Enum but no type_name was supplied in the .proto/descriptor, the field cannot be linked and CrossLink throws DescriptorValidationException.
Solutions
- Ensure every message/enum field's FieldDescriptorProto has Type set AND TypeName set to the fully-qualified type name (e.g. ".pkg.MyMessage").
- Regenerate descriptors with protoc instead of constructing them manually.
- Validate the descriptor proto before BuildFrom by walking fields and checking TypeName for MESSAGE/ENUM types.
- If descriptor data is corrupted, re-embed the descriptor from a fresh protoc run.
Example fix
// before
var field = new FieldDescriptorProto { Name = "item", Number = 1, Type = FieldDescriptorProto.Type.TypeMessage }; // no TypeName
// after
var field = new FieldDescriptorProto { Name = "item", Number = 1, Type = FieldDescriptorProto.Type.TypeMessage, TypeName = ".myproto.Item" }; Defensive patterns
Strategy: validation
Validate before calling
bool ValidDescriptor(FileDescriptorProto f) => f.MessageType.All(m => m.Field.All(fd => fd.Type != FieldDescriptorProto.Type.TypeMessage && fd.Type != FieldDescriptorProto.Type.TypeEnum || !string.IsNullOrEmpty(fd.TypeName)));
Try / catch
try { descriptor.BuildFrom(...); } catch (DescriptorValidationException e) { log.LogError($"Field {e.Message}: check type_name in descriptor"); } Prevention
- Always generate descriptors with protoc, never hand-build FieldDescriptorProtos for message/enum fields.
- Set both Type and TypeName when constructing FieldDescriptorProto programmatically.
- Add a unit test that builds all descriptors at startup to fail fast.
When it happens
Trigger: Building a FileDescriptor from a FileDescriptorProto (e.g. FileDescriptor.BuildFrom or FromGeneratedCode) where a message/enum-typed field in a DescriptorProto has FieldType.Message or FieldType.Enum but proto.type_name is null or empty.
Common situations: Hand-crafted or programmatically mutated FileDescriptorProtos; descriptors serialized by a non-protoc tool that omitted type_name; truncated or manually edited descriptor bytes embedded in generated code.
Understand the failure class
Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.
Related errors
- Missing name.
- " " is not a valid identifier.
- Field numbers must be positive integers.
- Invalid public dependency index.
- Invalid public dependency
AI-assisted analysis of XINCGer/Unity3DTraining@016f98412e (2026-09-12).
Data as JSON: /api/errors/49fdbedc990ba0ae.
Report an issue: GitHub.
Appendix: source
Thrown at NetWorkAndResources/Socket_Protobuff/Assets/Plugins/Google.Protobuf/Reflection/FieldDescriptor.cs:351
}
else if (fieldType == FieldType.Enum)
{
if (!(typeDescriptor is EnumDescriptor))
{
throw new DescriptorValidationException(this, "\"" + Proto.TypeName + "\" is not an enum type.");
}
enumType = (EnumDescriptor)typeDescriptor;
}
else
{
throw new DescriptorValidationException(this, "Field with primitive type has type_name.");
}
}
else
{
if (fieldType == FieldType.Message || fieldType == FieldType.Enum)
{
throw new DescriptorValidationException(this, "Field with message or enum type missing type_name.");
}
}
// Note: no attempt to perform any default value parsing
File.DescriptorPool.AddFieldByNumber(this);
if (ContainingType != null && ContainingType.Proto.Options != null && ContainingType.Proto.Options.MessageSetWireFormat)
{
throw new DescriptorValidationException(this, "MessageSet format is not supported.");
}
accessor = CreateAccessor();
}
private IFieldAccessor CreateAccessor()
{
// If we're given no property name, that's because we really don't want an accessor.
// (At the moment, that means it's a map entry message...)View on GitHub (pinned to 016f98412e)