XINCGer/Unity3DTraining · error · InvalidProtocolBufferException

Expected object value for Any

Error message

Expected object value for Any

What it means

An Any value's canonical JSON is an object containing at minimum an "@type" key (plus the packed inner message fields). MergeAny reads the first token and, if it is not StartObject, throws this InvalidProtocolBufferException before it can scan for @type.

Solutions

  1. Emit Any as a JSON object: {"@type": "type.googleapis.com/pkg.Msg", ...inner fields}.
  2. If you have a raw inner message JSON, wrap it: merge the type URL key into the inner object before parsing.
  3. If a plain string was intended, change the schema field type from Any to string.
  4. Catch InvalidProtocolBufferException and inspect the payload to confirm the Any field's JSON shape.

Example fix

// before: Any as a bare string
{"detail": "type.googleapis.com/foo.Bar"}

// after
{"detail": {"@type": "type.googleapis.com/foo.Bar", "id": 42}}
Defensive patterns

Strategy: validation

Validate before calling

// Any fields must be objects containing @type
function validateAnyField(payload, name) {
  const v = payload[name];
  if (v !== undefined && (typeof v !== 'object' || v === null || Array.isArray(v))) {
    throw new Error(`${name} (google.protobuf.Any) must be a JSON object with @type`);
  }
}

Type guard

function isAnyLike(v) { return v !== null && typeof v === 'object' && !Array.isArray(v) && typeof v['@type'] === 'string'; }

Try / catch

try { var msg = JsonParser.Default.Parse<T>(json); }
catch (InvalidProtocolBufferException ex) when (ex.Message == "Expected object value for Any") { /* reject payload: Any must be an object */ }

Prevention

When it happens

Trigger: Calling JsonParser.Parse where a google.protobuf.Any field receives a JSON string (e.g. the bare type URL), a number, an array, or null instead of an object, e.g. {"detail": "type.googleapis.com/foo.Bar"}.

Common situations: APIs that serialize Any as just the type URL or the inner message without the object wrapper; clients that stringify the Any value; confusion between Any and StringValue/bytes fields.

Understand the failure class

Background: "cannot parse invalid wire-format data", "cannot unmarshal", "failed unmarshalling": protobuf unmarshal errors explained — this error's family across 10 libraries.

Related errors


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

Appendix: source

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

            {
                throw new InvalidProtocolBufferException("Expected object value for Struct");
            }
            tokenizer.PushBack(token);

            var field = message.Descriptor.Fields[Struct.FieldsFieldNumber];
            MergeMapField(message, field, tokenizer);
        }

        private void MergeAny(IMessage message, JsonTokenizer tokenizer)
        {
            // Record the token stream until we see the @type property. At that point, we can take the value, consult
            // the type registry for the relevant message, and replay the stream, omitting the @type property.
            var tokens = new List<JsonToken>();

            var token = tokenizer.Next();
            if (token.Type != JsonToken.TokenType.StartObject)
            {
                throw new InvalidProtocolBufferException("Expected object value for Any");
            }
            int typeUrlObjectDepth = tokenizer.ObjectDepth;

            // The check for the property depth protects us from nested Any values which occur before the type URL
            // for *this* Any.
            while (token.Type != JsonToken.TokenType.Name ||
                token.StringValue != JsonFormatter.AnyTypeUrlField ||
                tokenizer.ObjectDepth != typeUrlObjectDepth)
            {
                tokens.Add(token);
                token = tokenizer.Next();

                if (tokenizer.ObjectDepth < typeUrlObjectDepth)
                {
                    throw new InvalidProtocolBufferException("Any message with no @type");
                }
            }

View on GitHub (pinned to 016f98412e)