XINCGer/Unity3DTraining · error · InvalidProtocolBufferException

Expected string value for Duration

Error message

Expected string value for Duration

What it means

MergeDuration requires the Duration well-known type to appear in JSON as a string (e.g. "3.5s"). If the JSON token for a google.protobuf.Duration field is not a string value (number, object, bool, null), the parser throws 'Expected string value for Duration'.

Solutions

  1. Encode the Duration as a string with an 's' suffix: "5s", "3.000000001s".
  2. Fix the producing side to follow the canonical protobuf JSON mapping for Duration.
  3. Catch InvalidProtocolBufferException and convert numeric inputs to the string form before parsing.
  4. If you control the schema, consider using int64 seconds fields instead of Duration when interop matters.

Example fix

// before
string json = "{\"duration\": 5}";
// after
string json = "{\"duration\": \"5s\"}";
Defensive patterns

Strategy: type-guard

Validate before calling

bool IsDurationStringToken(object token) => token is string;
// caller-side: ensure the JSON field value is a string before parsing

Type guard

bool IsJsonString(object v) => v is string s && s != null;
// or for JSON: if (field.Value.Type != JTokenType.String) reject;

Try / catch

try { var d = JsonParser.Default.Parse<Duration>(json); }
catch (InvalidProtocolBufferException ex) when (ex.Message.StartsWith("Expected string value for Duration"))
{ log.Warn("Duration field must be a string like \"5s\""); throw; }

Prevention

When it happens

Trigger: Parsing JSON where a Duration field is given as a number ({"duration": 5}), an object ({"duration": {"seconds": 5}}), or null instead of the canonical string form ({"duration": "5s"}) via JsonParser.Parse<T>.

Common situations: JSON hand-written by developers assuming seconds-as-number; JSON from other serializers that map Duration to a numeric or struct; clients not following the protobuf JSON mapping spec.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


AI-assisted analysis of XINCGer/Unity3DTraining@016f98412e (2026-09-12). Data as JSON: /api/errors/e6550db94230a48f. Report an issue: GitHub.

Appendix: source

Thrown at NetWorkAndResources/Socket_Protobuff/Assets/Plugins/Google.Protobuf/JsonParser.cs:863

                    if (timestamp.Seconds < Timestamp.UnixSecondsAtBclMinValue || timestamp.Seconds > Timestamp.UnixSecondsAtBclMaxValue)
                    {
                        throw new InvalidProtocolBufferException("Invalid Timestamp value: " + token.StringValue);
                    }
                }
                message.Descriptor.Fields[Timestamp.SecondsFieldNumber].Accessor.SetValue(message, timestamp.Seconds);
                message.Descriptor.Fields[Timestamp.NanosFieldNumber].Accessor.SetValue(message, timestamp.Nanos);
            }
            catch (FormatException)
            {
                throw new InvalidProtocolBufferException("Invalid Timestamp value: " + token.StringValue);
            }
        }

        private static void MergeDuration(IMessage message, JsonToken token)
        {
            if (token.Type != JsonToken.TokenType.StringValue)
            {
                throw new InvalidProtocolBufferException("Expected string value for Duration");
            }
            var match = DurationRegex.Match(token.StringValue);
            if (!match.Success)
            {
                throw new InvalidProtocolBufferException("Invalid Duration value: " + token.StringValue);
            }
            var sign = match.Groups["sign"].Value;
            var secondsText = match.Groups["int"].Value;
            // Prohibit leading insignficant zeroes
            if (secondsText[0] == '0' && secondsText.Length > 1)
            {
                throw new InvalidProtocolBufferException("Invalid Duration value: " + token.StringValue);
            }
            var subseconds = match.Groups["subseconds"].Value;
            var multiplier = sign == "-" ? -1 : 1;

            try
            {

View on GitHub (pinned to 016f98412e)