babalae/better-genshin-impact · error · InvalidDataException

命名管道消息超过 {MaxPayloadLength} 字节限制。

Error message

命名管道消息超过 {MaxPayloadLength} 字节限制。

What it means

Thrown by ReadFrameAsync (the receive side of the IPC framing layer). After reading the 5-byte frame header, it interprets the first 4 bytes as a little-endian uint32 payload length. If that value exceeds MaxPayloadLength (1,048,576 bytes = 1 MiB), the frame is rejected before any payload allocation occurs, protecting against denial-of-service via oversized length fields.

Source

Thrown at BetterGenshinImpact/Service/Instance/InstanceIpcProtocol.cs:298

            span[sizeof(ulong)] == 1);
    }

    internal static async ValueTask<InstanceIpcFrame?> ReadFrameAsync(
        Stream stream,
        CancellationToken cancellationToken)
    {
        var header = new byte[FrameHeaderLength];
        var firstRead = await stream.ReadAsync(header.AsMemory(0, 1), cancellationToken).ConfigureAwait(false);
        if (firstRead == 0)
        {
            return null;
        }

        await stream.ReadExactlyAsync(header.AsMemory(1), cancellationToken).ConfigureAwait(false);
        var payloadLength = BinaryPrimitives.ReadUInt32LittleEndian(header);
        if (payloadLength > MaxPayloadLength)
        {
            throw new InvalidDataException($"命名管道消息超过 {MaxPayloadLength} 字节限制。");
        }

        var payloadType = (InstanceIpcPayloadType)header[sizeof(uint)];
        if (!Enum.IsDefined(payloadType))
        {
            throw new InvalidDataException($"未知命名管道载荷类型:{header[sizeof(uint)]}。");
        }

        var payload = new byte[checked((int)payloadLength)];
        if (payload.Length > 0)
        {
            await stream.ReadExactlyAsync(payload, cancellationToken).ConfigureAwait(false);
        }

        return new InstanceIpcFrame(payloadType, payload);
    }

    private static async ValueTask WriteFrameAsync(

View on GitHub (pinned to a7cb36712d)

Solutions

  1. Catch InvalidDataException in the connection receive loop and close the pipe so the accept/reconnect loops establish a fresh stream.
  2. If sending large data through WebView messages, chunk or externalize the data (write to a temp file and pass a path) instead of embedding it in the IPC envelope.
  3. Verify protocol version match between peers — a header layout change will cause every length field to be misread.
  4. Add logging of the raw header bytes and decoded length at the throw site to distinguish genuine oversize from stream corruption.
Defensive patterns

Strategy: try-catch

Try / catch

// In the receive loop:
try
{
    var frame = await InstanceIpcProtocol.ReadFrameAsync(stream, ct);
}
catch (InvalidDataException ex) when (ex.Message.Contains("字节限制"))
{
    _logger.LogError(ex, "收到超大帧,关闭连接");
    await connection.DisposeAsync();
}

Prevention

When it happens

Trigger: The peer (or a corrupt/malicious stream) sent a frame whose 4-byte length header decodes to a value greater than 1 MiB. In normal operation this should never happen — JSON envelopes and mouse frames are far smaller. A genuinely oversized JSON envelope (e.g., a WebView message embedding a multi-megabyte data payload) could trigger it, but more commonly the length field is garbage from stream misalignment or a crashed peer leaving partial data in the pipe buffer.

Common situations: A previous frame was misread (wrong byte count consumed), shifting the stream so the parser interprets payload data or a JSON string as a length header; an older/newer protocol version uses a different header layout; an attempt to send a very large embedded data blob through SendWebViewMessageAsync that serialized to > 1 MiB of JSON.

Related errors


AI-assisted analysis of babalae/better-genshin-impact@a7cb36712d (2026-08-13). Data as JSON: /api/errors/cebe056738f479f2. Report an issue: GitHub.