mgth/LittleBigMouse · error · IOException

Malformed MQTT remaining length.

Error message

Malformed MQTT remaining length.

What it means

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.

Solutions

  1. Treat the connection as unrecoverable: close it and reopen with OpenMqttAsync — MQTT framing cannot resync mid-packet.
  2. Check that only one reader consumes the stream concurrently (double readers desynchronize framing).
  3. Verify TLS/certificate setup is correct — a mis-decrypted stream produces garbage bytes that break length decoding.
  4. Log the raw bytes before the failure to identify whether the peer or the client state caused the desync.

Example fix

// before: retry reads on the same broken stream
var packet = await ReadPacketAsync(stream, token);
// after: any framing error means reconnect
try { var packet = await ReadPacketAsync(stream, token); }
catch (IOException e) when (e.Message.Contains("Malformed MQTT remaining length"))
{ await CloseAsync(); await OpenMqttAsync(token); }
Defensive patterns

Strategy: fallback

Validate before calling

// Only one reader should own the stream; assert before reading
if (readerRunning) throw new InvalidOperationException("A packet reader is already active on this MQTT stream.");

Type guard

static bool IsFinalLengthByte(byte encoded) => (encoded & 128) == 0;

Try / catch

try { var packet = await ReadPacketAsync(stream, token); }
catch (IOException e) when (e.Message.Contains("Malformed MQTT remaining length"))
{ await CloseAsync(); await OpenMqttAsync(token); // framing cannot resync: full reconnect }

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


AI-assisted analysis of mgth/LittleBigMouse@7a42f01d47 (2026-09-16). Data as JSON: /api/errors/f71742a94e44b025. Report an issue: GitHub.

Appendix: source

Thrown at LittleBigMouse.Plugins/LittleBigMouse.Plugin.Vcp.Avalonia/HisenseVidaa/VidaaMqttConnection.cs:248

        body.CopyTo(packet);
        return packet.ToArray();
    }

    static async Task<(byte Header, byte[] Payload)> ReadPacketAsync(
        Stream stream,
        CancellationToken cancellationToken)
    {
        var header = await ReadByteAsync(stream, cancellationToken).ConfigureAwait(false);
        var multiplier = 1;
        var length = 0;
        byte encoded;
        do
        {
            encoded = await ReadByteAsync(stream, cancellationToken).ConfigureAwait(false);
            length += (encoded & 127) * multiplier;
            multiplier *= 128;
            if (multiplier > 128 * 128 * 128 * 128)
                throw new IOException("Malformed MQTT remaining length.");
        } while ((encoded & 128) != 0);

        var payload = new byte[length];
        await stream.ReadExactlyAsync(payload, cancellationToken).ConfigureAwait(false);
        return (header, payload);
    }

    static async Task<byte> ReadByteAsync(Stream stream, CancellationToken cancellationToken)
    {
        var buffer = new byte[1];
        if (await stream.ReadAsync(buffer, cancellationToken).ConfigureAwait(false) != 1)
            throw new EndOfStreamException("VIDAA closed the MQTT connection.");
        return buffer[0];
    }

    static void WriteUtf8(Stream stream, string value)
    {
        var bytes = Encoding.UTF8.GetBytes(value);

View on GitHub (pinned to 7a42f01d47)