XINCGer/Unity3DTraining · error · DescriptorValidationException
Field with primitive type has type_name.
Error message
Field with primitive type has type_name.
What it means
Fields with a primitive/scalar type (numbers, bool, string, bytes) must not set type_name; only message and enum fields use it. During CrossLink, if a field has no inline type resolution but carries a TypeName and its field type is scalar, DescriptorValidationException is thrown.
Solutions
- Clear Proto.TypeName for scalar-typed fields before building the descriptor set.
- Regenerate descriptors from the .proto so protoc emits type_name only for message/enum fields.
- Sanitize imported FileDescriptorProtos: drop type_name whenever Type is a primitive type.
Example fix
// before
new FieldDescriptorProto { Name = "count", Type = TYPE_INT32, TypeName = "MyApp.Count" }
// after
new FieldDescriptorProto { Name = "count", Type = TYPE_INT32 } Defensive patterns
Strategy: validation
Validate before calling
var scalar = field.Proto.Type is FieldDescriptorProto.Types.Type.Int32 or FieldDescriptorProto.Types.Type.Int64 or FieldDescriptorProto.Types.Type.Uint32 or FieldDescriptorProto.Types.Type.Uint64 or FieldDescriptorProto.Types.Type.Float or FieldDescriptorProto.Types.Type.Double or FieldDescriptorProto.Types.Type.Bool or FieldDescriptorProto.Types.Type.String or FieldDescriptorProto.Types.Type.Bytes;
if (scalar && field.Proto.TypeName != "")
throw new InvalidDataException("Scalar field " + field.Name + " must not set type_name"); Type guard
bool TypeNameAllowed(FieldDescriptorProto f) =>
f.Type == FieldDescriptorProto.Types.Type.Message || f.Type == FieldDescriptorProto.Types.Type.Enum || f.TypeName == ""; Try / catch
try { descriptor = FileDescriptor.BuildFromByteStrings(data); }
catch (DescriptorValidationException ex) when (ex.Message == "Field with primitive type has type_name.")
{ log.LogError(ex, "Clear type_name on scalar fields"); } Prevention
- Clear TypeName whenever changing a field's type to a scalar in descriptor-building code.
- Let protoc emit descriptors rather than hand-assembling FieldDescriptorProtos.
- Sanitize imported descriptor sets: drop type_name for all primitive types.
When it happens
Trigger: A FieldDescriptorProto with a scalar Type (e.g. TYPE_INT32) AND a non-empty TypeName — e.g. hand-built protos that set both, or generated descriptors where type_name was not cleared when the type was changed to a scalar.
Common situations: Changing a field from a message to a scalar in code without clearing TypeName; custom code generators emitting TypeName for all fields; descriptor manipulation tools that copy field templates.
Understand the failure class
Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.
Related errors
- "TypeName" is not a message type.
- "TypeName" is not an enum type.
- Expected an object
- Unsupported JSON token type
- Unsupported conversion from JSON number for field type
AI-assisted analysis of XINCGer/Unity3DTraining@016f98412e (2026-09-12).
Data as JSON: /api/errors/8b069c3ba06b79b5.
Report an issue: GitHub.
Appendix: source
Thrown at NetWorkAndResources/Socket_Protobuff/Assets/Plugins/Google.Protobuf/Reflection/FieldDescriptor.cs:344
}
messageType = (MessageDescriptor)typeDescriptor;
if (Proto.DefaultValue != "")
{
throw new DescriptorValidationException(this, "Messages can't have default values.");
}
}
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.");
}View on GitHub (pinned to 016f98412e)