mgth/LittleBigMouse · error · EndOfStreamException

VIDAA closed the MQTT connection.

Error message

VIDAA closed the MQTT connection.

What it means

Thrown by ReadByteAsync when a read from the TV's MQTT stream returns zero bytes (EndOfStream), meaning the remote peer closed the connection. The library translates this into EndOfStreamException('VIDAA closed the MQTT connection.') so callers know the TV ended the session rather than the read failing locally.

Solutions

  1. Reopen the connection: catch EndOfStreamException, dispose the dead session, and call OpenMqttAsync again (optionally with backoff).
  2. Send periodic MQTT PINGREQ (the library's PingLoopAsync) so keep-alive requirements don't cause the TV to drop idle connections.
  3. Verify the TV is powered on, awake (not deep standby), and reachable on the network before reconnecting.
  4. Check for recurring drops at fixed intervals — that pattern indicates a keep-alive/idle timeout to tune rather than a transient fault.

Example fix

// before: single attempt, failure ends the session
await connection.OpenMqttAsync(token);
// after: reconnect with backoff when the TV closes the socket
try { await connection.OpenMqttAsync(token); }
catch (EndOfStreamException)
{ await Task.Delay(TimeSpan.FromSeconds(2), token); await connection.OpenMqttAsync(token); }
Defensive patterns

Strategy: retry

Validate before calling

// Probe reachability before (re)connecting
canConnect = await PingDeviceAsync(tvHost, timeoutMs: 1000); // TV must be on and reachable

Type guard

bool IsRemoteClosed(Exception e) => e is EndOfStreamException;

Try / catch

try { await connection.OpenMqttAsync(token); }
catch (EndOfStreamException)
{ await Task.Delay(backoff, token); await connection.OpenMqttAsync(token); }

Prevention

When it happens

Trigger: ReadByteAsync, called by the packet-header reader and ReadPacketAsync (ConnectAsync handshake or the ongoing read loop), gets a 0-byte result from stream.ReadAsync — the TV closed the TCP connection mid-handshake or during the session.

Common situations: TV powered off, went to standby, or rebooted; Wi-Fi/network interruption terminating the TCP session; TV closing idle connections due to keep-alive timeout; broker crash or firmware restart of the MQTT service.

Related errors


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

Appendix: source

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

        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);
        if (bytes.Length > ushort.MaxValue) throw new ArgumentOutOfRangeException(nameof(value));
        WriteUInt16(stream, (ushort)bytes.Length);
        stream.Write(bytes);
    }

    static void WriteUInt16(Stream stream, ushort value)
    {
        Span<byte> bytes = stackalloc byte[2];
        BinaryPrimitives.WriteUInt16BigEndian(bytes, value);
        stream.Write(bytes);
    }

View on GitHub (pinned to 7a42f01d47)