dotnet/aspnetcore · error · Error

Invalid payload.

Error message

Invalid payload.

What it means

Thrown by JsonHubProtocol's message-type switch when `parsedMessage.type` is not a `number`. After JSON.parse, every hub message must carry a numeric `type` discriminator (Invocation=1, StreamItem=2, Completion=3, StreamInvocation=4, CancelInvocation=5, Ping=6, Close=7, Ack=8, Sequence=9, etc.); a missing or non-numeric type cannot be dispatched and is rejected as an invalid payload.

Solutions

  1. Verify the server and client use the same SignalR JSON protocol version.
  2. Inspect the raw frame to confirm each message object includes a numeric `type`.
  3. If proxying/transforming frames, preserve the `type` field unchanged.
Defensive patterns

Strategy: type-guard

Validate before calling

function hasNumericType(m: any): boolean {
  return m && typeof m.type === "number";
}

Type guard

function isTypedHubMessage(m: any): m is { type: number } {
  return !!m && typeof m.type === "number";
}

Prevention

When it happens

Trigger: Receiving a JSON message that omits the `type` field, sets it to a string, or carries an out-of-range value that does not match any MessageType case (the throw fires before the switch handles known types because the type check happens up front).

Common situations: Interoperating with a hand-rolled/older server that omits `type`, a malformed proxy rewriting the payload, or a protocol-version mismatch (e.g. server speaks an older JSON protocol without type field).

Related errors


AI-assisted analysis of dotnet/aspnetcore@3600ca084e (2026-08-11). Data as JSON: /api/errors/0b73b144e23012a1. Report an issue: GitHub.

Appendix: source

Thrown at src/SignalR/clients/ts/signalr/src/JsonHubProtocol.ts:49

            throw new Error("Invalid input for JSON hub protocol. Expected a string.");
        }

        if (!input) {
            return [];
        }

        if (logger === null) {
            logger = NullLogger.instance;
        }

        // Parse the messages
        const messages = TextMessageFormat.parse(input);

        const hubMessages = [];
        for (const message of messages) {
            const parsedMessage = JSON.parse(message) as HubMessage;
            if (typeof parsedMessage.type !== "number") {
                throw new Error("Invalid payload.");
            }
            switch (parsedMessage.type) {
                case MessageType.Invocation:
                    this._isInvocationMessage(parsedMessage);
                    break;
                case MessageType.StreamItem:
                    this._isStreamItemMessage(parsedMessage);
                    break;
                case MessageType.Completion:
                    this._isCompletionMessage(parsedMessage);
                    break;
                case MessageType.Ping:
                    // Single value, no need to validate
                    break;
                case MessageType.Close:
                    // All optional values, no need to validate
                    break;
                case MessageType.Ack:

View on GitHub (pinned to 3600ca084e)