dotnet/aspnetcore · error

Invalid payload.

Error message

Invalid payload.

What it means

Thrown in _parseMessage when an individual frame extracted by BinaryMessageFormat.parse has length 0. BinaryMessageFormat already split the buffer on varint length prefixes, so a zero-length frame means the wire data was structurally broken (a length prefix pointed at an empty payload). This is a defense against feeding garbage to the msgpack decoder.

Source

Thrown at src/SignalR/clients/ts/signalr-protocol-msgpack/src/MessagePackHubProtocol.ts:129

                return this._writeCompletion(message as CompletionMessage);
            case MessageType.Ping:
                return BinaryMessageFormat.write(SERIALIZED_PING_MESSAGE);
            case MessageType.CancelInvocation:
                return this._writeCancelInvocation(message as CancelInvocationMessage);
            case MessageType.Close:
                return this._writeClose();
            case MessageType.Ack:
                return this._writeAck(message as AckMessage);
            case MessageType.Sequence:
                return this._writeSequence(message as SequenceMessage);
            default:
                throw new Error("Invalid message type.");
        }
    }

    private _parseMessage(input: Uint8Array, logger: ILogger): HubMessage | null {
        if (input.length === 0) {
            throw new Error("Invalid payload.");
        }

        const properties = this._decoder.decode(input) as any;
        if (properties.length === 0 || !(properties instanceof Array)) {
            throw new Error("Invalid payload.");
        }

        const messageType = properties[0] as MessageType;

        switch (messageType) {
            case MessageType.Invocation:
                return this._createInvocationMessage(this._readHeaders(properties), properties);
            case MessageType.StreamItem:
                return this._createStreamItemMessage(this._readHeaders(properties), properties);
            case MessageType.Completion:
                return this._createCompletionMessage(this._readHeaders(properties), properties);
            case MessageType.Ping:
                return this._createPingMessage(properties);

View on GitHub (pinned to 294cab2f9b)

Solutions

  1. Capture the raw bytes at the transport layer and verify the varint length prefixes are consistent with the available bytes before parsing.
  2. Check the SignalR server and client protocol versions match (both should support MessagePack v2).
  3. Inspect the connection for middleware/proxies that may alter the binary stream (e.g. a text-mode reverse proxy).
  4. Add a try/catch around the connection's onreceive handler to log the offending buffer length and reconnect.

Example fix

// before
const hubMessages = protocol.parseMessages(rawBuffer, logger);

// after
try {
  const hubMessages = protocol.parseMessages(rawBuffer, logger);
} catch (e) {
  logger.log(LogLevel.Error, 'Corrupt msgpack frame, reconnecting: ' + e.message);
  await connection.stop();
  await connection.start();
}
Defensive patterns

Strategy: try-catch

Validate before calling

// validate varint length prefixes before parsing
function framesLookComplete(buffer: ArrayBuffer): boolean {
  const u = new Uint8Array(buffer);
  for (let i = 0; i < u.length;) {
    let len = 0, shift = 0, n = 0, b;
    do { b = u[i + n]; len |= (b & 0x7f) << shift; shift += 7; n++; }
    while (n < 5 && (b & 0x80) !== 0);
    if (len === 0) return false; // a zero-length frame will trigger error 102
    i += n + len;
    if (i > u.length) return false;
  }
  return true;
}

Try / catch

try {
  const msgs = protocol.parseMessages(buffer, logger);
} catch (e) {
  if (e.message === 'Invalid payload.') {
    logger.log(LogLevel.Error, 'Zero-length msgpack frame; reconnecting.');
    await connection.start();
    return;
  }
  throw e;
}

Prevention

When it happens

Trigger: Corrupt or truncated binary frame where a varint length prefix is followed by zero bytes; a man-in-the-middle or proxy that strips payload bytes; manually constructing a buffer with a 0x00 length prefix then data.

Common situations: Network interruption mid-frame leaving a partial buffer that the length prefix claims is empty; a bug in a custom transport that pre-slices frames incorrectly; version skew where an old server emits a frame shape the client cannot interpret.

Related errors


AI-assisted analysis of dotnet/aspnetcore@294cab2f9b (2026-08-06). Data as JSON: /api/errors/e7a004bd939ef754. Report an issue: GitHub.