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

  1. Change one of the conflicting fields' Number so every field in the message has a unique number.
  2. When adding fields programmatically, track the highest used number per message and allocate the next free one.
  3. Fix the source .proto (two fields with the same number) and regenerate with protoc.
  4. 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

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


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)