XINCGer/Unity3DTraining · error · InvalidOperationException
Struct fields cannot have an empty key or a null value.
Error message
Struct fields cannot have an empty key or a null value.
What it means
JsonFormatter.WriteStruct throws InvalidOperationException when a google.protobuf.Struct's fields map contains an empty string key or a null value entry. Struct is defined to have non-empty keys and non-null Value messages; the formatter enforces this invariant.
Solutions
- Remove null-valued and empty-key entries before formatting, or represent nulls as Value.ForNull()
- Validate the source dictionary before converting it into a Struct
- Use the generated Struct/Value APIs (Value.ForString etc.) instead of raw map mutation
- Sanitize third-party JSON before packing into a Struct
Example fix
// before structMsg.Fields[""] = null; // after structMsg.Fields["key"] = Value.ForNull(); // non-empty key; use Value.ForNull for JSON null
Defensive patterns
Strategy: validation
Validate before calling
bool structIsValid = structMsg.Fields.All(kv => !string.IsNullOrEmpty(kv.Key) && kv.Value != null);
Type guard
static bool IsValidStructEntry(KeyValuePair<string, Value> e) => !string.IsNullOrEmpty(e.Key) && e.Value != null;
Try / catch
try { json = formatter.Format(structMsg); } catch (InvalidOperationException ex) when (ex.Message.Contains("Struct fields")) { /* sanitize struct and retry */ } Prevention
- Sanitize source dictionaries: drop null values and empty keys
- Use Value.ForNull() to represent JSON nulls
- Build Structs via generated APIs, not raw map mutation
When it happens
Trigger: Manually mutating the Struct's fields dictionary (Struct.Fields[key] = null, or adding ""); deserializing malformed data into a Struct and then formatting it; reflection-based code inserting null Values.
Common situations: Hand-constructing Struct values from user dictionaries that contain empty keys or nulls; bridges from JSON.NET/other serializers that preserve null entries; corrupted payloads.
Understand the failure class
Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.
Related errors
- Value message must contain a value for the oneof.
- Unexpected case in struct field:
- Invalid field type
- Unable to format value of type
- Type registry has no descriptor for type name '
AI-assisted analysis of XINCGer/Unity3DTraining@016f98412e (2026-09-12).
Data as JSON: /api/errors/b449f1c1b95f3a41.
Report an issue: GitHub.
Appendix: source
Thrown at NetWorkAndResources/Socket_Protobuff/Assets/Plugins/Google.Protobuf/JsonFormatter.cs:576
writer.Write(NameValueSeparator);
writer.Write('"');
writer.Write(data.ToBase64());
writer.Write('"');
writer.Write(" }");
}
private void WriteStruct(TextWriter writer, IMessage message)
{
writer.Write("{ ");
IDictionary fields = (IDictionary)message.Descriptor.Fields[Struct.FieldsFieldNumber].Accessor.GetValue(message);
bool first = true;
foreach (DictionaryEntry entry in fields)
{
string key = (string)entry.Key;
IMessage value = (IMessage)entry.Value;
if (string.IsNullOrEmpty(key) || value == null)
{
throw new InvalidOperationException("Struct fields cannot have an empty key or a null value.");
}
if (!first)
{
writer.Write(PropertySeparator);
}
WriteString(writer, key);
writer.Write(NameValueSeparator);
WriteStructFieldValue(writer, value);
first = false;
}
writer.Write(first ? "}" : " }");
}
private void WriteStructFieldValue(TextWriter writer, IMessage message)
{
var specifiedField = message.Descriptor.Oneofs[0].Accessor.GetCaseFieldDescriptor(message);
if (specifiedField == null)View on GitHub (pinned to 016f98412e)