{"record":{"id":"38d5b8b4928967a2","repo":"XINCGer/Unity3DTraining","slug":"non-normalized-duration-value","errorCode":null,"errorMessage":"Non-normalized duration value","messagePattern":"Non-normalized duration value","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"NetWorkAndResources/Socket_Protobuff/Assets/Plugins/Google.Protobuf/WellKnownTypes/DurationPartial.cs","lineNumber":224,"sourceCode":"                    builder.Append('-');\n                }\n\n                builder.Append(seconds.ToString(\"d\", CultureInfo.InvariantCulture));\n                AppendNanoseconds(builder, Math.Abs(nanoseconds));\n                builder.Append(\"s\\\"\");\n                return builder.ToString();\n            }\n            if (diagnosticOnly)\n            {\n                // Note: the double braces here are escaping for braces in format strings.\n                return string.Format(CultureInfo.InvariantCulture,\n                    \"{{ \\\"@warning\\\": \\\"Invalid Duration\\\", \\\"seconds\\\": \\\"{0}\\\", \\\"nanos\\\": {1} }}\",\n                    seconds,\n                    nanoseconds);\n            }\n            else\n            {\n                throw new InvalidOperationException(\"Non-normalized duration value\");\n            }\n        }\n\n        /// <summary>\n        /// Returns a string representation of this <see cref=\"Duration\"/> for diagnostic purposes.\n        /// </summary>\n        /// <remarks>\n        /// Normally the returned value will be a JSON string value (including leading and trailing quotes) but\n        /// when the value is non-normalized or out of range, a JSON object representation will be returned\n        /// instead, including a warning. This is to avoid exceptions being thrown when trying to\n        /// diagnose problems - the regular JSON formatter will still throw an exception for non-normalized\n        /// values.\n        /// </remarks>\n        /// <returns>A string representation of this value.</returns>\n        public string ToDiagnosticString()\n        {\n            return ToJson(Seconds, Nanos, true);\n        }","sourceCodeStart":206,"sourceCodeEnd":242,"githubUrl":"https://github.com/XINCGer/Unity3DTraining/blob/016f98412ea5e11756b286736f479b66ab6216d5/NetWorkAndResources/Socket_Protobuff/Assets/Plugins/Google.Protobuf/WellKnownTypes/DurationPartial.cs#L206-L242","documentation":"Duration.ToJson refuses to serialize a Duration whose Seconds/Nanos are not normalized (nanos outside [-999999999, 999999999] with mismatched signs, or both zero-signed wrongly). The JSON mapping for Duration requires a canonical 'Ns' string, so the library throws InvalidOperationException instead of emitting invalid protobuf-JSON. Note ToDiagnosticString catches this path and emits a warning JSON only for out-of-range values, but non-normalized values still throw.","triggerScenarios":"Calling ToDiagnosticString()/ToJson() on a Duration constructed or deserialized with non-normalized values, e.g. Nanos=1500000000 (should be Seconds+=1, Nanos=500000000) or Seconds=1, Nanos=-500000000 (mixed signs).","commonSituations":"Manually building Duration objects with hand-computed nanos; doing arithmetic on Seconds/Nanos fields without renormalizing; migrating data from another protobuf implementation that didn't normalize; decoding durations from non-Google middleware that skips validation.","solutions":["Normalize the Duration before serializing: seconds += nanos / 1_000_000_000; nanos %= 1_000_000_000 (keeping sign consistent)","Use Duration.FromTimeSpan(TimeSpan) or Duration.FromDays/Hours/Minutes/Seconds/Milliseconds instead of setting Seconds/Nanos by hand","If values come from the wire, re-parse with Duration.Parser which validates normalization","Catch InvalidOperationException in the ToString/serialization path and log the raw Seconds/Nanos for diagnosis"],"exampleFix":"// before\nvar d = new Duration { Seconds = 3, Nanos = 1_500_000_000 };\nvar s = d.ToDiagnosticString(); // throws\n// after\nvar d = new Duration { Seconds = 4, Nanos = 500_000_000 };\n// or programmatically:\nlong totalNanos = 3L * 1_000_000_000 + 1_500_000_000;\nvar d2 = new Duration { Seconds = totalNanos / 1_000_000_000, Nanos = (int)(totalNanos % 1_000_000_000) };\nvar s2 = d2.ToDiagnosticString(); // \"4.500000000s\"","handlingStrategy":"validation","validationCode":"static bool IsNormalizedDuration(Duration d) => d.Nanos >= -999_999_999 && d.Nanos <= 999_999_999 && (d.Seconds < 0 ? d.Nanos <= 0 : d.Seconds > 0 ? d.Nanos >= 0 : true);","typeGuard":"static bool IsValidDuration(Duration d) => d != null && d.Nanos is >= -999_999_999 and <= 999_999_999;","tryCatchPattern":"try { return d.ToDiagnosticString(); } catch (InvalidOperationException ex) { log.Warn(ex, \"Non-normalized duration: {Seconds}.{Nanos}\", d.Seconds, d.Nanos); return $\"{d.Seconds}s {d.Nanos}ns (non-normalized)\"; }","preventionTips":["Always build Durations with FromTimeSpan/FromDays/FromHours/... helpers","Renormalize after any manual Seconds/Nanos arithmetic","Validate values at deserialization boundaries before use"],"tags":["protobuf","c-sharp","duration","serialization"],"backgroundTag":"invalid-argument-value","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"}