XINCGer/Unity3DTraining · error · InvalidProtocolBufferException
Invalid enum value:
Error message
Invalid enum value:
What it means
Google.Protobuf's JsonParser throws InvalidProtocolBufferException when converting JSON to a protobuf message. In ParseSingleStringValue, a JSON string field whose FieldType is Enum is resolved via the enum descriptor's FindValueByName; if the string is not a declared enum value name, this error is thrown. The protobuf JSON spec requires enum values in JSON to be the value name (e.g. "VALUE_A"), not an alias or arbitrary text.
Solutions
- Use the exact enum value name declared in the .proto file for the field's enum type
- Check field.EnumType.FullName's declared values (e.g. dump the EnumDescriptor values) and match the JSON string to one of them
- If you must send a number, use a JSON number instead of a string so the parser takes the numeric path
- Regenerate the C# protobuf classes from the current .proto so descriptors contain the value names you send
- Add the missing value or an allow_alias entry to the proto enum if the name is legitimately new
Example fix
// before
var msg = MessageParser.Parse('{"state": "2"}'); // throws: no enum value named "2"
// after
var msg = MessageParser.Parse('{"state": "STATE_INACTIVE"}'); // matches declared proto value Defensive patterns
Strategy: validation
Validate before calling
bool IsValidEnumJson(string json, MessageDescriptor d) {
// For each enum field, check the string against EnumType.FindValueByName before parsing.
foreach (var f in d.Fields.InFieldNumberOrder())
if (f.FieldType == FieldType.Enum && json.Contains("\"" + f.JsonName + "\": \""))
if (f.EnumType.FindValueByName(ExtractEnumString(json, f.JsonName)) == null) return false;
return true;
} Type guard
bool IsKnownEnumValue(string text, EnumDescriptor e) => e.FindValueByName(text) != null;
Try / catch
try { return JsonParser.Default.Parse<T>(json); }
catch (InvalidProtocolBufferException ex) when (ex.Message.StartsWith("Invalid enum value")) {
logger.LogWarning(ex, "Unknown enum name in JSON");
return null; // or repair/migrate the payload
} Prevention
- Keep proto enums stable; never rename values without a compatibility plan
- Match enum strings exactly — they are case-sensitive
- Send enum values by their declared proto name, not numerics or ad-hoc strings
- Regenerate C# stubs whenever the .proto changes
When it happens
Trigger: Calling JsonParser.Parse<T>(json) (directly or via JsonFormatter/Parse on a message containing enum fields) where a string value for an enum-typed field does not exactly match a registered enum value name, e.g. sending "ACTIVE" when the proto declares only STATUS_ACTIVE, or sending a numeric enum as a string like "2" when no alias named "2" exists.
Common situations: Older/newer .proto versions between client and server so the enum name was renamed or removed; hand-written JSON using numeric or ad-hoc strings for enums; code generators out of sync after regenerating C# stubs; typos or case mismatches (JSON enum names are case-sensitive here).
Understand the failure class
Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.
Related errors
- Unsupported conversion from JSON string for field type
- Invalid field type
- Unable to format value of type
- Type registry has no descriptor for type name '
- Struct fields cannot have an empty key or a null value.
AI-assisted analysis of XINCGer/Unity3DTraining@016f98412e (2026-09-12).
Data as JSON: /api/errors/d6b9cf40c30ee0ab.
Report an issue: GitHub.
Appendix: source
Thrown at NetWorkAndResources/Socket_Protobuff/Assets/Plugins/Google.Protobuf/JsonParser.cs:716
case FieldType.SInt64:
case FieldType.SFixed64:
return ParseNumericString<long>(text, long.Parse);
case FieldType.UInt64:
case FieldType.Fixed64:
return ParseNumericString<ulong>(text, ulong.Parse);
case FieldType.Double:
double d = ParseNumericString<double>(text, double.Parse);
ValidateInfinityAndNan(text, double.IsPositiveInfinity(d), double.IsNegativeInfinity(d), double.IsNaN(d));
return d;
case FieldType.Float:
float f = ParseNumericString<float>(text, float.Parse);
ValidateInfinityAndNan(text, float.IsPositiveInfinity(f), float.IsNegativeInfinity(f), float.IsNaN(f));
return f;
case FieldType.Enum:
var enumValue = field.EnumType.FindValueByName(text);
if (enumValue == null)
{
throw new InvalidProtocolBufferException("Invalid enum value: " + text + " for enum type: " + field.EnumType.FullName);
}
// Just return it as an int, and let the CLR convert it.
return enumValue.Number;
default:
throw new InvalidProtocolBufferException("Unsupported conversion from JSON string for field type " + field.FieldType);
}
}
/// <summary>
/// Creates a new instance of the message type for the given field.
/// </summary>
private static IMessage NewMessageForField(FieldDescriptor field)
{
return field.MessageType.Parser.CreateTemplate();
}
private static T ParseNumericString<T>(string text, Func<string, NumberStyles, IFormatProvider, T> parser)
{View on GitHub (pinned to 016f98412e)