{"record":{"id":"9b00888f62b98945","repo":"XINCGer/Unity3DTraining","slug":"expected-string-value-for-fieldmask","errorCode":null,"errorMessage":"Expected string value for FieldMask","messagePattern":"Expected string value for FieldMask","errorType":"exception","errorClass":"InvalidProtocolBufferException","httpStatus":null,"severity":"error","filePath":"NetWorkAndResources/Socket_Protobuff/Assets/Plugins/Google.Protobuf/JsonParser.cs","lineNumber":907,"sourceCode":"                }\n                if (!Duration.IsNormalized(seconds, nanos))\n                {\n                    throw new InvalidProtocolBufferException(\"Invalid Duration value: \" + token.StringValue);\n                }\n                message.Descriptor.Fields[Duration.SecondsFieldNumber].Accessor.SetValue(message, seconds);\n                message.Descriptor.Fields[Duration.NanosFieldNumber].Accessor.SetValue(message, nanos);\n            }\n            catch (FormatException)\n            {\n                throw new InvalidProtocolBufferException(\"Invalid Duration value: \" + token.StringValue);\n            }\n        }\n\n        private static void MergeFieldMask(IMessage message, JsonToken token)\n        {\n            if (token.Type != JsonToken.TokenType.StringValue)\n            {\n                throw new InvalidProtocolBufferException(\"Expected string value for FieldMask\");\n            }\n            // TODO: Do we *want* to remove empty entries? Probably okay to treat \"\" as \"no paths\", but \"foo,,bar\"?\n            string[] jsonPaths = token.StringValue.Split(FieldMaskPathSeparators, StringSplitOptions.RemoveEmptyEntries);\n            IList messagePaths = (IList)message.Descriptor.Fields[FieldMask.PathsFieldNumber].Accessor.GetValue(message);\n            foreach (var path in jsonPaths)\n            {\n                messagePaths.Add(ToSnakeCase(path));\n            }\n        }\n\n        // Ported from src/google/protobuf/util/internal/utility.cc\n        private static string ToSnakeCase(string text)\n        {\n            var builder = new StringBuilder(text.Length * 2);\n            // Note: this is probably unnecessary now, but currently retained to be as close as possible to the\n            // C++, whilst still throwing an exception on underscores.\n            bool wasNotUnderscore = false;  // Initialize to false for case 1 (below)\n            bool wasNotCap = false;","sourceCodeStart":889,"sourceCodeEnd":925,"githubUrl":"https://github.com/XINCGer/Unity3DTraining/blob/016f98412ea5e11756b286736f479b66ab6216d5/NetWorkAndResources/Socket_Protobuff/Assets/Plugins/Google.Protobuf/JsonParser.cs#L889-L925","documentation":"MergeFieldMask requires a google.protobuf.FieldMask to appear in JSON as a comma-separated string of field paths (e.g. \"user.displayName,photo\"). If the JSON token is not a string value (object, array, number, null), the parser throws 'Expected string value for FieldMask'.","triggerScenarios":"Parsing JSON where a FieldMask field is given as an array ([\"user\"]) or an object ({\"paths\": [...]}) instead of the canonical string form \"user,photo\" via JsonParser.Parse<T>.","commonSituations":"Clients sending FieldMask as JSON arrays (a common intuition); JSON from non-protobuf serializers; API consumers unfamiliar with the protobuf JSON mapping for well-known types.","solutions":["Send the FieldMask as a single comma-separated string: \"user.displayName,photo\".","Convert arrays of paths to string.Join(\",\", paths) before serializing.","Catch InvalidProtocolBufferException and map array-form masks to the string form before parsing.","Follow the canonical protobuf JSON mapping documented for google.protobuf.FieldMask."],"exampleFix":"// before\nstring json = \"{\\\"mask\\\": [\\\"user\\\", \\\"photo\\\"]}\";\n// after\nstring json = \"{\\\"mask\\\": \\\"user,photo\\\"}\";","handlingStrategy":"type-guard","validationCode":"// Convert array-form field masks to canonical string form before parsing\nstring ToFieldMaskJson(IEnumerable<string> paths) =>\n    \"\\\"\" + string.Join(\",\", paths) + \"\\\"\";","typeGuard":"bool IsFieldMaskString(object v) => v is string s && s.Split(',').All(p => p.Length > 0);","tryCatchPattern":"try { var msg = JsonParser.Default.Parse<T>(json); }\ncatch (InvalidProtocolBufferException ex) when (ex.Message == \"Expected string value for FieldMask\")\n{ log.Warn(\"FieldMask must be a comma-separated string\"); throw new ArgumentException(\"fieldMask must be a string like \\\"user,photo\\\"\", ex); }","preventionTips":["Always send FieldMask as one comma-separated string, not an array/object","Convert client-side path arrays with string.Join(\",\", paths)","Document the canonical FieldMask JSON form in your API docs","Reject array-form masks at your ingress with a clear 400 message"],"tags":["protobuf","json-parsing","fieldmask","type-mismatch"],"backgroundTag":"type-mismatch","analyzedSha":"016f98412ea5e11756b286736f479b66ab6216d5","analyzedAt":"2026-09-12T01:08:58.711Z","contentChangedAt":"2026-09-12T01:08:58.711Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}