babalae/better-genshin-impact · error · InvalidDataException

未知命名管道载荷类型:{header[sizeof(uint)]}。

Error message

未知命名管道载荷类型:{header[sizeof(uint)]}。

What it means

Thrown by ReadFrameAsync after the payload length check passes. The 5th byte of the frame header is cast to InstanceIpcPayloadType and validated via Enum.IsDefined. If the byte value is not 1 (Utf8Json), 2 (RelativeMouseBatch), or 3 (RelativeMouseResult), the frame type is unrecognized and rejected.

Source

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

    {
        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(
        Stream stream,
        InstanceIpcPayloadType payloadType,
        ReadOnlyMemory<byte> payload,
        CancellationToken cancellationToken)
    {
        if (payload.Length > MaxPayloadLength)

View on GitHub (pinned to a7cb36712d)

Solutions

  1. Ensure all BetterGI instances (Primary, ChildSession, WebView) in the same user session run the same application version.
  2. Catch InvalidDataException in the receive loop and dispose the connection to trigger a clean reconnect.
  3. Log the raw type byte value alongside the frame to identify whether it is a version issue (consistent new value) or corruption (random values).
  4. If developing a new payload type, update InstanceIpcPayloadType in all peers before deploying.
Defensive patterns

Strategy: try-catch

Type guard

// Check if a payload type byte is a known type
static bool IsKnownPayloadType(byte typeByte)
    => Enum.IsDefined((InstanceIpcPayloadType)typeByte);

Try / catch

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 payload type byte in the frame header is 0 or >= 4. This occurs when a newer protocol version introduced a new payload type that this receiver does not know about, when the stream is misaligned so a payload data byte is interpreted as the type field, or when the pipe buffer contains residual data from a crashed previous session.

Common situations: Running mixed versions of BetterGI where one side was updated to send a new frame type; stream misalignment caused by a bug in the receive loop reading the wrong number of bytes; a security tool or pipe relay injecting or dropping bytes; Windows named pipe kernel buffer not fully flushed after a previous process crash.

Related errors


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