XINCGer/Unity3DTraining · error · DescriptorValidationException
Field number has already been used in " " by field " ".
Error message
Field number {field.FieldNumber}has already been used in "{field.ContainingType.FullName}" by field "{old.Name}". What it means
DescriptorPool.AddFieldByNumber throws DescriptorValidationException when two fields within the same message type are assigned the same field number. Field numbers are the wire-format identity of a field, so duplicates within one message are ambiguous and forbidden. (The message text is missing a space after the number — a cosmetic quirk of this port.)
Solutions
- Change one of the conflicting fields' Number so every field in the message has a unique number.
- When adding fields programmatically, track the highest used number per message and allocate the next free one.
- Fix the source .proto (two fields with the same number) and regenerate with protoc.
- Never reuse/remove numbers on the wire without reserving them (reserved ranges) to avoid conflicts in evolving schemas.
Example fix
// before
new FieldDescriptorProto { Name = "a", Number = 1, ... },
new FieldDescriptorProto { Name = "b", Number = 1, ... } // duplicate
// after
new FieldDescriptorProto { Name = "a", Number = 1, ... },
new FieldDescriptorProto { Name = "b", Number = 2, ... } Defensive patterns
Strategy: validation
Validate before calling
static void AssertUniqueFieldNumbers(DescriptorProto msg)
{
var seen = new HashSet<int>();
foreach (var f in msg.Fields)
if (!seen.Add(f.Number))
throw new InvalidOperationException($"Duplicate field number {f.Number} in {msg.Name}");
} Try / catch
try
{
var fd = FileDescriptor.BuildFromByteString(bytes, dependencies);
}
catch (DescriptorValidationException ex) when (ex.Message.Contains("has already been used in"))
{
// renumber the duplicated field and rebuild
} Prevention
- Use a per-message max-number allocator when building fields programmatically
- Reserve field numbers in evolving schemas to prevent collisions
- Run buf lint / protoc validation in CI before building descriptors
When it happens
Trigger: Building a FileDescriptor where two FieldDescriptorProto entries of the same DescriptorProto share a Number — e.g. hand-constructed descriptors adding field 1 twice, a duplicated field entry in a serialized FileDescriptorSet, or generated descriptors from a broken custom codegen.
Common situations: Programmatic schema builders appending fields with auto-incremented numbers that reset or collide; copying an existing field and forgetting to change its number; merging schemas from branches where two developers picked the same field number.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- Field numbers must be positive integers.
- " " is already defined (as something other than a package)…
- " " is already defined in file " ".
- Missing name.
- " " is not a valid identifier.
AI-assisted analysis of XINCGer/Unity3DTraining@016f98412e (2026-09-12).
Data as JSON: /api/errors/529329e70fa54832.
Report an issue: GitHub.
Appendix: source
Thrown at NetWorkAndResources/Socket_Protobuff/Assets/Plugins/Google.Protobuf/Reflection/DescriptorPool.cs:234
internal EnumValueDescriptor FindEnumValueByNumber(EnumDescriptor enumDescriptor, int number)
{
EnumValueDescriptor ret;
enumValuesByNumber.TryGetValue(new DescriptorIntPair(enumDescriptor, number), out ret);
return ret;
}
/// <summary>
/// Adds a field to the fieldsByNumber table.
/// </summary>
/// <exception cref="DescriptorValidationException">A field with the same
/// containing type and number already exists.</exception>
internal void AddFieldByNumber(FieldDescriptor field)
{
DescriptorIntPair key = new DescriptorIntPair(field.ContainingType, field.FieldNumber);
FieldDescriptor old;
if (fieldsByNumber.TryGetValue(key, out old))
{
throw new DescriptorValidationException(field, "Field number " + field.FieldNumber +
"has already been used in \"" +
field.ContainingType.FullName +
"\" by field \"" + old.Name + "\".");
}
fieldsByNumber[key] = field;
}
/// <summary>
/// Adds an enum value to the enumValuesByNumber table. If an enum value
/// with the same type and number already exists, this method does nothing.
/// (This is allowed; the first value defined with the number takes precedence.)
/// </summary>
internal void AddEnumValueByNumber(EnumValueDescriptor enumValue)
{
DescriptorIntPair key = new DescriptorIntPair(enumValue.EnumDescriptor, enumValue.Number);
if (!enumValuesByNumber.ContainsKey(key))
{
enumValuesByNumber[key] = enumValue;View on GitHub (pinned to 016f98412e)