XINCGer/Unity3DTraining · error · DescriptorValidationException

Property not found in

Error message

Property {propertyName} not found in {ContainingType.ClrType}

What it means

CreateAccessor links a descriptor field to the generated C# class by reflection: it looks up a property whose name is derived from the field name on ContainingType.ClrType. If the CLR type has no such property, the descriptor and the generated code are out of sync and a DescriptorValidationException is thrown.

Solutions

  1. Regenerate the C# code with protoc (and the matching plugin) from the same .proto that produced the descriptor bytes.
  2. Ensure the descriptor data and the message assembly come from the same schema version.
  3. Verify messageDescriptor.ClrType passed during construction actually corresponds to the containing message in the descriptor.
  4. Clean and rebuild so stale generated files are not mixed with new descriptors.

Example fix

// before: stale descriptor paired with regenerated assembly
FileDescriptor.FromGeneratedCode(oldDescriptorData, new[] { dep }, new MessageDescriptor[] { new OldMsg() });
// after: regenerate both from the same .proto
FileDescriptor.FromGeneratedCode(freshDescriptorData, deps, new MessageDescriptor[] { new RegeneratedMsg() });
Defensive patterns

Strategy: validation

Validate before calling

bool ClrTypeMatches(MessageDescriptor md, System.Type clrType) => md.Proto.Field.All(f => clrType.GetProperty(GeneratedPropertyName(f.Name)) != null);

Try / catch

try { FromGeneratedCode(...); } catch (ArgumentException e) when (e.InnerException is DescriptorValidationException dve && dve.Message.Contains("not found in")) { log.LogError("Descriptor/assembly mismatch — regenerate code"); }

Prevention

When it happens

Trigger: FileDescriptor.BuildFrom/FromGeneratedCode where the embedded descriptor contains a field whose generated property does not exist on the passed CLR type (mismatched descriptor vs assembly), or a customClrType/descriptor pair built by hand.

Common situations: Descriptor bytes regenerated (field added/renamed) while the old generated C# assembly is still loaded; passing the wrong message type to descriptor construction; stale plugin output after renaming a field.

Related errors


AI-assisted analysis of XINCGer/Unity3DTraining@016f98412e (2026-09-12). Data as JSON: /api/errors/8d969b9b5e28fc11. Report an issue: GitHub.

Appendix: source

Thrown at NetWorkAndResources/Socket_Protobuff/Assets/Plugins/Google.Protobuf/Reflection/FieldDescriptor.cs:377

            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...)
            if (propertyName == null)
            {
                return null;
            }
            var property = ContainingType.ClrType.GetProperty(propertyName);
            if (property == null)
            {
                throw new DescriptorValidationException(this, "Property " + propertyName + " not found in " + ContainingType.ClrType);
            }
            return IsMap ? new MapFieldAccessor(property, this)
                : IsRepeated ? new RepeatedFieldAccessor(property, this)
                : (IFieldAccessor)new SingleFieldAccessor(property, this);
        }
    }
}

View on GitHub (pinned to 016f98412e)