{"record":{"id":"f71742a94e44b025","repo":"mgth/LittleBigMouse","slug":"malformed-mqtt-remaining-length","errorCode":null,"errorMessage":"Malformed MQTT remaining length.","messagePattern":"Malformed MQTT remaining length\\.","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"LittleBigMouse.Plugins/LittleBigMouse.Plugin.Vcp.Avalonia/HisenseVidaa/VidaaMqttConnection.cs","lineNumber":248,"sourceCode":"        body.CopyTo(packet);\n        return packet.ToArray();\n    }\n\n    static async Task<(byte Header, byte[] Payload)> ReadPacketAsync(\n        Stream stream,\n        CancellationToken cancellationToken)\n    {\n        var header = await ReadByteAsync(stream, cancellationToken).ConfigureAwait(false);\n        var multiplier = 1;\n        var length = 0;\n        byte encoded;\n        do\n        {\n            encoded = await ReadByteAsync(stream, cancellationToken).ConfigureAwait(false);\n            length += (encoded & 127) * multiplier;\n            multiplier *= 128;\n            if (multiplier > 128 * 128 * 128 * 128)\n                throw new IOException(\"Malformed MQTT remaining length.\");\n        } while ((encoded & 128) != 0);\n\n        var payload = new byte[length];\n        await stream.ReadExactlyAsync(payload, cancellationToken).ConfigureAwait(false);\n        return (header, payload);\n    }\n\n    static async Task<byte> ReadByteAsync(Stream stream, CancellationToken cancellationToken)\n    {\n        var buffer = new byte[1];\n        if (await stream.ReadAsync(buffer, cancellationToken).ConfigureAwait(false) != 1)\n            throw new EndOfStreamException(\"VIDAA closed the MQTT connection.\");\n        return buffer[0];\n    }\n\n    static void WriteUtf8(Stream stream, string value)\n    {\n        var bytes = Encoding.UTF8.GetBytes(value);","sourceCodeStart":230,"sourceCodeEnd":266,"githubUrl":"https://github.com/mgth/LittleBigMouse/blob/7a42f01d47d99d223b8ee33ba4019af82adf1c48/LittleBigMouse.Plugins/LittleBigMouse.Plugin.Vcp.Avalonia/HisenseVidaa/VidaaMqttConnection.cs#L230-L266","documentation":"Thrown in ReadPacketAsync while decoding the MQTT variable-length remaining-length header: if the continuation loop runs past the maximum four bytes (multiplier exceeds 128^4), the framing is corrupt and the library throws IOException. This indicates a desynchronized stream — the client is no longer reading where packets begin, or the peer sent garbage.","triggerScenarios":"ReadPacketAsync (driven by ConnectAsync and the packet reader loop) reads remaining-length bytes whose continuation bit keeps being set beyond four encoded bytes — corrupt TCP stream, resync after a dropped/torn connection, or a peer sending non-MQTT bytes.","commonSituations":"Network middleboxes or flaky Wi-Fi corrupting/truncating the TLS stream; reading from a stale socket after the TV dropped the connection; connecting to a port that speaks a different protocol; a buffer/offset bug upstream leaving partial bytes in the stream.","solutions":["Treat the connection as unrecoverable: close it and reopen with OpenMqttAsync — MQTT framing cannot resync mid-packet.","Check that only one reader consumes the stream concurrently (double readers desynchronize framing).","Verify TLS/certificate setup is correct — a mis-decrypted stream produces garbage bytes that break length decoding.","Log the raw bytes before the failure to identify whether the peer or the client state caused the desync."],"exampleFix":"// before: retry reads on the same broken stream\nvar packet = await ReadPacketAsync(stream, token);\n// after: any framing error means reconnect\ntry { var packet = await ReadPacketAsync(stream, token); }\ncatch (IOException e) when (e.Message.Contains(\"Malformed MQTT remaining length\"))\n{ await CloseAsync(); await OpenMqttAsync(token); }","handlingStrategy":"fallback","validationCode":"// Only one reader should own the stream; assert before reading\nif (readerRunning) throw new InvalidOperationException(\"A packet reader is already active on this MQTT stream.\");","typeGuard":"static bool IsFinalLengthByte(byte encoded) => (encoded & 128) == 0;","tryCatchPattern":"try { var packet = await ReadPacketAsync(stream, token); }\ncatch (IOException e) when (e.Message.Contains(\"Malformed MQTT remaining length\"))\n{ await CloseAsync(); await OpenMqttAsync(token); // framing cannot resync: full reconnect }","preventionTips":["Never allow concurrent readers on the same MQTT stream","Reconnect on any framing error — mid-packet resync is impossible","Validate TLS certificates so a bad decryption path can't feed garbage bytes","Log raw bytes preceding the failure to distinguish peer corruption from client bugs"],"tags":["mqtt","protocol-violation","corrupt-stream","iot"],"backgroundTag":"invalid-argument-format","analyzedSha":"7a42f01d47d99d223b8ee33ba4019af82adf1c48","analyzedAt":"2026-09-16T00:35:00.514Z","contentChangedAt":"2026-09-16T00:35:00.514Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}