XINCGer/Unity3DTraining · error · DescriptorValidationException
Enums must contain at least one value.
Error message
Enums must contain at least one value.
What it means
EnumDescriptor construction throws DescriptorValidationException when an EnumDescriptorProto contains zero values. Protobuf requires every enum to declare at least one value because fields of that enum type need a valid default value (the first declared value, which must be 0 in proto3).
Solutions
- Add at least one enum value, conventionally a zero-valued default (proto3 requires the first value to have number 0).
- If building descriptors programmatically, add an EnumValueProto entry before building the FileDescriptor.
- Inspect the serialized descriptor set for enums with empty 'value' lists and fix the producer tooling.
- Validate descriptor protos before building (assert proto.Value.Count > 0 for every enum).
Example fix
// before
var e = new EnumDescriptorProto { Name = "Status" }; // no values
fileProto.EnumTypes.Add(e);
// after
var e = new EnumDescriptorProto
{
Name = "Status",
Values = { new EnumValueDescriptorProto { Name = "STATUS_UNKNOWN", Number = 0 } }
};
fileProto.EnumTypes.Add(e); Defensive patterns
Strategy: validation
Validate before calling
static void AssertEnumsHaveValues(FileDescriptorProto file)
{
foreach (var e in file.EnumTypes)
if (e.Values.Count == 0)
throw new InvalidOperationException($"Enum {e.Name} has no values");
} Type guard
bool HasValues(EnumDescriptorProto e) => e.Value.Count > 0;
Try / catch
try
{
var fd = FileDescriptor.BuildFromByteString(bytes, dependencies);
}
catch (DescriptorValidationException ex) when (ex.Message.Contains("at least one value"))
{
// reject the descriptor set / add a default zero value and rebuild
} Prevention
- Always define a zero-valued default enum value first (proto3 requirement)
- Validate descriptor protos before building
- When generating enums dynamically, seed a UNKNOWN = 0 value
When it happens
Trigger: Building a FileDescriptor from an EnumDescriptorProto with an empty Value collection — e.g. new EnumDescriptorProto { Name = "E" } with no values added, a serialized FileDescriptorSet whose enum has no EnumValueProto entries, or a custom codegen emitting empty enums.
Common situations: Dynamically generating proto descriptors and forgetting to seed a default enum value; tooling stripping all enum values during schema transformation; tests constructing minimal descriptor scaffolding without populating values.
Understand the failure class
Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.
Related errors
- " " is already defined (as something other than a package)…
- " " is already defined in file " ".
- Missing name.
- " " is not a valid identifier.
- Field number has already been used in " " by field " ".
AI-assisted analysis of XINCGer/Unity3DTraining@016f98412e (2026-09-12).
Data as JSON: /api/errors/09164cd4d23e0814.
Report an issue: GitHub.
Appendix: source
Thrown at NetWorkAndResources/Socket_Protobuff/Assets/Plugins/Google.Protobuf/Reflection/EnumDescriptor.cs:59
public sealed class EnumDescriptor : DescriptorBase
{
private readonly EnumDescriptorProto proto;
private readonly MessageDescriptor containingType;
private readonly IList<EnumValueDescriptor> values;
private readonly Type clrType;
internal EnumDescriptor(EnumDescriptorProto proto, FileDescriptor file, MessageDescriptor parent, int index, Type clrType)
: base(file, file.ComputeFullName(parent, proto.Name), index)
{
this.proto = proto;
this.clrType = clrType;
containingType = parent;
if (proto.Value.Count == 0)
{
// We cannot allow enums with no values because this would mean there
// would be no valid default value for fields of this type.
throw new DescriptorValidationException(this, "Enums must contain at least one value.");
}
values = DescriptorUtil.ConvertAndMakeReadOnly(proto.Value,
(value, i) => new EnumValueDescriptor(value, file, this, i));
File.DescriptorPool.AddSymbol(this);
}
internal EnumDescriptorProto Proto { get { return proto; } }
/// <summary>
/// The brief name of the descriptor's target.
/// </summary>
public override string Name { get { return proto.Name; } }
/// <summary>
/// The CLR type for this enum. For generated code, this will be a CLR enum type.
/// </summary>View on GitHub (pinned to 016f98412e)