XINCGer/Unity3DTraining · error · ArgumentException
Cannot read from property
Error message
Cannot read from property
What it means
OneofAccessor's constructor requires the CLR case-discriminator property (e.g. 'MyOneofCase') to be readable, since it binds a getter delegate used to determine which oneof field is set. If PropertyInfo.CanRead is false it throws ArgumentException. This indicates a mismatch between the generated message type and the descriptor wiring.
Solutions
- Use the standard generated message classes so the Case property has a public getter.
- Pass the property obtained via ClrType.GetProperty(name + "Case") on the generated type rather than an unrelated property.
- Regenerate the C# code with protoc so case properties match the descriptor.
Example fix
// before
var prop = typeof(Msg).GetProperty("Choice", BindingFlags.NonPublic | BindingFlags.SetProperty);
new OneofAccessor(prop, clearMethod, oneofDesc); // throws
// after
var prop = typeof(Msg).GetProperty("ChoiceCase"); // readable generated case property
new OneofAccessor(prop, clearMethod, oneofDesc); Defensive patterns
Strategy: validation
Validate before calling
var prop = typeof(Msg).GetProperty(oneofName + "Case");
if (prop == null || !prop.CanRead) throw new InvalidOperationException($"Readable '{oneofName}Case' property required"); Type guard
bool IsReadableOneofCase(PropertyInfo p) => p != null && p.CanRead;
Try / catch
try { accessor = new OneofAccessor(prop, clearMethod, desc); } catch (ArgumentException ex) { log.Error($"Bad oneof property: {ex.Message}"); throw; } Prevention
- Only construct accessors from standard protoc-generated message types.
- Check PropertyInfo.CanRead before constructing reflection accessors.
When it happens
Trigger: Constructing a OneofAccessor directly (or via OneofDescriptor.CreateAccessor) with a PropertyInfo for the oneof case property that is write-only or otherwise unreadable.
Common situations: Custom reflection tooling building accessors over generated protobuf classes, or generated code whose case property was replaced/hidden by partial-class shadowing.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- Property Case not found in
- Method Clear not found in
- Multiple values specified for oneof
- FieldDescriptorProto.oneof_index is out of range for type
- FieldDescriptors can only be compared to other…
AI-assisted analysis of XINCGer/Unity3DTraining@016f98412e (2026-09-12).
Data as JSON: /api/errors/beab3c20a9c0e035.
Report an issue: GitHub.
Appendix: source
Thrown at NetWorkAndResources/Socket_Protobuff/Assets/Plugins/Google.Protobuf/Reflection/OneofAccessor.cs:52
using System.Reflection;
// using Google.Protobuf.Compatibility;
namespace Google.Protobuf.Reflection
{
/// <summary>
/// Reflection access for a oneof, allowing clear and "get case" actions.
/// </summary>
public sealed class OneofAccessor
{
private readonly Func<IMessage, int> caseDelegate;
private readonly Action<IMessage> clearDelegate;
private OneofDescriptor descriptor;
internal OneofAccessor(PropertyInfo caseProperty, MethodInfo clearMethod, OneofDescriptor descriptor)
{
if (!caseProperty.CanRead)
{
throw new ArgumentException("Cannot read from property");
}
this.descriptor = descriptor;
caseDelegate = ReflectionUtil.CreateFuncIMessageT<int>(caseProperty.GetGetMethod());
this.descriptor = descriptor;
clearDelegate = ReflectionUtil.CreateActionIMessage(clearMethod);
}
/// <summary>
/// Gets the descriptor for this oneof.
/// </summary>
/// <value>
/// The descriptor of the oneof.
/// </value>
public OneofDescriptor Descriptor { get { return descriptor; } }
/// <summary>
/// Clears the oneof in the specified message.View on GitHub (pinned to 016f98412e)