{"record":{"id":"b4d775bfb3b7109c","repo":"XINCGer/Unity3DTraining","slug":"expected-string-value-for-timestamp","errorCode":null,"errorMessage":"Expected string value for Timestamp","messagePattern":"Expected string value for Timestamp","errorType":"exception","errorClass":"InvalidProtocolBufferException","httpStatus":null,"severity":"error","filePath":"NetWorkAndResources/Socket_Protobuff/Assets/Plugins/Google.Protobuf/JsonParser.cs","lineNumber":787,"sourceCode":"        /// Checks that any infinite/NaN values originated from the correct text.\n        /// This corrects the lenient whitespace handling of double.Parse/float.Parse, as well as the\n        /// way that Mono parses out-of-range values as infinity.\n        /// </summary>\n        private static void ValidateInfinityAndNan(string text, bool isPositiveInfinity, bool isNegativeInfinity, bool isNaN)\n        {\n            if ((isPositiveInfinity && text != \"Infinity\") ||\n                (isNegativeInfinity && text != \"-Infinity\") ||\n                (isNaN && text != \"NaN\"))\n            {\n                throw new InvalidProtocolBufferException(\"Invalid numeric value: \" + text);\n            }\n        }\n\n        private static void MergeTimestamp(IMessage message, JsonToken token)\n        {\n            if (token.Type != JsonToken.TokenType.StringValue)\n            {\n                throw new InvalidProtocolBufferException(\"Expected string value for Timestamp\");\n            }\n            var match = TimestampRegex.Match(token.StringValue);\n            if (!match.Success)\n            {\n                throw new InvalidProtocolBufferException(\"Invalid Timestamp value: \" + token.StringValue);\n            }\n            var dateTime = match.Groups[\"datetime\"].Value;\n            var subseconds = match.Groups[\"subseconds\"].Value;\n            var offset = match.Groups[\"offset\"].Value;\n\n            try\n            {\n                DateTime parsed = DateTime.ParseExact(\n                    dateTime,\n                    \"yyyy-MM-dd'T'HH:mm:ss\",\n                    CultureInfo.InvariantCulture,\n                    DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal);\n                // TODO: It would be nice not to have to create all these objects... easy to optimize later though.","sourceCodeStart":769,"sourceCodeEnd":805,"githubUrl":"https://github.com/XINCGer/Unity3DTraining/blob/016f98412ea5e11756b286736f479b66ab6216d5/NetWorkAndResources/Socket_Protobuff/Assets/Plugins/Google.Protobuf/JsonParser.cs#L769-L805","documentation":"The protobuf JSON mapping represents google.protobuf.Timestamp exclusively as an RFC 3339 string (e.g. '2024-01-15T10:30:00Z'). MergeTimestamp first checks that the incoming JSON token is a string; if a Timestamp field receives a number, object, or other token type, it throws InvalidProtocolBufferException('Expected string value for Timestamp').","triggerScenarios":"JsonParser.Parse<T> on messages containing google.protobuf.Timestamp fields where the JSON value is a number (Unix epoch seconds/millis) or an object ({\"seconds\":...}), e.g. {\"createdAt\": 1705314600}.","commonSituations":"APIs mixing Unix timestamps with proto JSON; JavaScript Date objects serialized as numbers by JSON.stringify alternatives; hand-written JSON assuming epoch-style timestamps; migration from another serializer's convention.","solutions":["Convert the epoch value to an RFC 3339 UTC string before parsing, e.g. DateTimeOffset.FromUnixTimeSeconds(sec).UtcDateTime.ToString(\"o\")","Emit the timestamp as 'YYYY-MM-DDTHH:mm:ss[.fff]Z' (RFC 3339) in the JSON","If the field is truly a numeric epoch, change the proto field to int64/int32 instead of Timestamp","Fix the JSON producer's serializer settings to render DateTime/DateTimeOffset as ISO 8601 strings"],"exampleFix":"// before\nvar json = \"{\\\"createdAt\\\": \" + unixSeconds + \"}\"; // number for Timestamp\n// after\nvar iso = DateTimeOffset.FromUnixTimeSeconds(unixSeconds).UtcDateTime.ToString(\"o\");\nvar json = \"{\\\"createdAt\\\": \\\"\" + iso + \"\\\"}\"; // \"2024-01-15T10:30:00Z\"","handlingStrategy":"validation","validationCode":"bool IsTimestampJsonString(object token) => token is string s &&\n    System.Text.RegularExpressions.Regex.IsMatch(s,\n        @\"^\\d{4}-\\d{2}-\\d{2}[Tt]\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?([Zz]|[+-]\\d{2}:\\d{2})$\");","typeGuard":"bool IsStringToken(object token) => token is string;","tryCatchPattern":"try { return JsonParser.Default.Parse<T>(json); }\ncatch (InvalidProtocolBufferException ex) when (ex.Message.Contains(\"Expected string value for Timestamp\")) {\n    logger.LogWarning(ex, \"Timestamp sent as non-string (e.g. epoch number)\");\n    return null;\n}","preventionTips":["Configure serializers to render dates as ISO 8601/RFC 3339 strings","Never feed epoch numbers into google.protobuf.Timestamp fields","Convert Unix time with DateTimeOffset.FromUnixTimeSeconds(...).UtcDateTime.ToString(\"o\")"],"tags":["protobuf","json","timestamp","rfc3339"],"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"}