{"record":{"id":"c896bddcdf7de012","repo":"babalae/better-genshin-impact","slug":"json-frame-payloadtype","errorCode":null,"errorMessage":"预期 JSON 帧，实际为 {frame.PayloadType}。","messagePattern":"预期 JSON 帧，实际为 (.+?)。","errorType":"exception","errorClass":"InvalidDataException","httpStatus":null,"severity":"error","filePath":"BetterGenshinImpact/Service/Instance/InstanceIpcProtocol.cs","lineNumber":138,"sourceCode":"\n    internal static async ValueTask WriteJsonAsync(\n        Stream stream,\n        InstanceIpcEnvelope envelope,\n        CancellationToken cancellationToken)\n    {\n        var payload = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(envelope, SerializerSettings));\n        await WriteFrameAsync(\n            stream,\n            InstanceIpcPayloadType.Utf8Json,\n            payload,\n            cancellationToken).ConfigureAwait(false);\n    }\n\n    internal static InstanceIpcEnvelope ReadJson(InstanceIpcFrame frame)\n    {\n        if (frame.PayloadType != InstanceIpcPayloadType.Utf8Json)\n        {\n            throw new InvalidDataException($\"预期 JSON 帧，实际为 {frame.PayloadType}。\");\n        }\n\n        return JsonConvert.DeserializeObject<InstanceIpcEnvelope>(\n                   Encoding.UTF8.GetString(frame.Payload),\n                   SerializerSettings)\n               ?? throw new InvalidDataException(\"命名管道 JSON 消息为空。\");\n    }\n\n    internal static async ValueTask WriteRelativeMouseBatchAsync(\n        Stream stream,\n        ulong firstSequence,\n        IReadOnlyList<RelativeMouseSample> samples,\n        CancellationToken cancellationToken)\n    {\n        if (samples.Count is <= 0 or > 64)\n        {\n            throw new ArgumentOutOfRangeException(nameof(samples), \"相对鼠标批次必须包含 1 到 64 个样本。\");\n        }","sourceCodeStart":120,"sourceCodeEnd":156,"githubUrl":"https://github.com/babalae/better-genshin-impact/blob/a7cb36712dcb409be610257d877fcea3597e9d6b/BetterGenshinImpact/Service/Instance/InstanceIpcProtocol.cs#L120-L156","documentation":"Thrown by InstanceIpcProtocol.ReadJson when the frame's PayloadType is not Utf8Json. ReadJson expects a JSON envelope but received a binary frame (RelativeMouseBatch or RelativeMouseResult). This indicates the receive-loop frame dispatch is out of sync with what the peer actually sent.","triggerScenarios":"A frame ordering/state-machine desync: the receive loop routes a frame to ReadJson when the peer sent a different payload type, or a peer implementation sends an unexpected frame type on the JSON channel.","commonSituations":"Protocol version skew between root and child; a peer bug that writes the wrong payload-type byte; in rare cases, stream corruption causing the dispatch to misroute.","solutions":["Restart both BetterGI instances so they re-establish a clean pipe session.","Ensure both instances run the same BetterGI build to rule out dispatch-logic differences.","If it reproduces on the same build, capture a trace of the raw frames — this is a dispatch-logic bug."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"if (frame.PayloadType != InstanceIpcPayloadType.Utf8Json)\n{\n    throw new InvalidDataException($\"预期 JSON 帧，实际为 {frame.PayloadType}。\");\n}","typeGuard":"static bool IsJsonFrame(InstanceIpcFrame frame) => frame.PayloadType == InstanceIpcPayloadType.Utf8Json;","tryCatchPattern":"try\n{\n    var envelope = InstanceIpcProtocol.ReadJson(frame.Value);\n}\ncatch (InvalidDataException ex) when (ex.Message.Contains(\"预期 JSON 帧\"))\n{\n    logger.LogError(ex, \"Frame type mismatch in JSON reader; restart instances\");\n}","preventionTips":["Run matching BetterGI builds on both ends of the pipe.","Restart instances when frame-type errors appear to reset the dispatch state machine.","If reproducing, trace raw payload-type bytes to distinguish corruption from logic mismatch."],"tags":["ipc","protocol","serialization","named-pipe"],"backgroundTag":null,"analyzedSha":"a7cb36712dcb409be610257d877fcea3597e9d6b","analyzedAt":"2026-08-13T16:44:57.548Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}