babalae/better-genshin-impact · error · InvalidDataException

相对鼠标处理结果帧无效。

Error message

相对鼠标处理结果帧无效。

What it means

Thrown by ReadRelativeMouseResult after the payload type check passes but the payload content is invalid. The result frame must be exactly RelativeMouseResultLength (9 bytes = sizeof(ulong) + sizeof(byte)) and the boolean byte at offset sizeof(ulong) must be 0 or 1. A wrong length or a boolean byte greater than 1 means the frame is structurally corrupt.

Source

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

        await WriteFrameAsync(
            stream,
            InstanceIpcPayloadType.RelativeMouseResult,
            payload,
            cancellationToken).ConfigureAwait(false);
    }

    internal static RelativeMouseResult ReadRelativeMouseResult(InstanceIpcFrame frame)
    {
        if (frame.PayloadType != InstanceIpcPayloadType.RelativeMouseResult)
        {
            throw new InvalidDataException($"预期相对鼠标处理结果帧,实际为 {frame.PayloadType}。");
        }

        var span = frame.Payload.AsSpan();
        if (span.Length != RelativeMouseResultLength || span[sizeof(ulong)] > 1)
        {
            throw new InvalidDataException("相对鼠标处理结果帧无效。");
        }

        return new RelativeMouseResult(
            BinaryPrimitives.ReadUInt64LittleEndian(span),
            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;
        }

View on GitHub (pinned to a7cb36712d)

Solutions

  1. Verify both peers use the same RelativeMouseResultLength constant (sizeof(ulong) + sizeof(byte) = 9) — any change must be deployed to all instances simultaneously.
  2. Catch InvalidDataException in the receive loop and dispose the connection to force a clean reconnect via the accept/reconnect loops.
  3. If writing test fixtures, ensure result frames are constructed via WriteRelativeMouseResultAsync rather than hand-encoding bytes.
  4. Check for named pipe stream corruption — if this recurs, investigate whether a firewall, antivirus, or pipe proxy is altering the byte stream.
Defensive patterns

Strategy: try-catch

Validate before calling

// Validate frame structure before calling ReadRelativeMouseResult
static bool IsValidRelativeMouseResultFrame(InstanceIpcFrame frame)
{
    var span = frame.Payload.AsSpan();
    return span.Length == 9 && span[sizeof(ulong)] <= 1;
}

Try / catch

try
{
    var result = InstanceIpcProtocol.ReadRelativeMouseResult(frame);
}
catch (InvalidDataException)
{
    // Frame is corrupt — close connection to force resync
    await connection.DisposeAsync();
}

Prevention

When it happens

Trigger: A frame arrives with PayloadType == RelativeMouseResult but its payload is not exactly 9 bytes, or byte[8] (the Handled flag) is > 1. This can happen if the sender wrote a partial/truncated payload, if the stream was interrupted mid-write and the next read consumed stale bytes, or if the binary layout was changed in one peer but not the other.

Common situations: Named pipe connection dropped mid-write causing a short frame that gets concatenated with the next frame's header; a protocol version change that altered RelativeMouseResultLength without updating both peers; test code that hand-crafts a result frame with an incorrect payload size.

Related errors


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