{"record":{"id":"0aa6cdd738dae650","repo":"mgth/LittleBigMouse","slug":"the-vidaa-mqtt-connection-is-closed","errorCode":null,"errorMessage":"The VIDAA MQTT connection is closed.","messagePattern":"The VIDAA MQTT connection is closed\\.","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"LittleBigMouse.Plugins/LittleBigMouse.Plugin.Vcp.Avalonia/HisenseVidaa/VidaaMqttConnection.cs","lineNumber":197,"sourceCode":"        catch (Exception e)\n        {\n            Console.Error.WriteLine($\"VIDAA MQTT keepalive stopped: {e.Message}\");\n            MarkDisconnected();\n        }\n    }\n\n    async Task WriteMqttPacketAsync(byte header, byte[] body, CancellationToken cancellationToken)\n    {\n        using var packet = new MemoryStream();\n        packet.WriteByte(header);\n        WriteRemainingLength(packet, body.Length);\n        packet.Write(body);\n        await WritePacketAsync(packet.ToArray(), cancellationToken).ConfigureAwait(false);\n    }\n\n    async Task WritePacketAsync(byte[] packet, CancellationToken cancellationToken)\n    {\n        var stream = _stream ?? throw new IOException(\"The VIDAA MQTT connection is closed.\");\n        await _writeLock.WaitAsync(cancellationToken).ConfigureAwait(false);\n        try\n        {\n            await stream.WriteAsync(packet, cancellationToken).ConfigureAwait(false);\n            await stream.FlushAsync(cancellationToken).ConfigureAwait(false);\n        }\n        catch\n        {\n            MarkDisconnected();\n            throw;\n        }\n        finally\n        {\n            _writeLock.Release();\n        }\n    }\n\n    internal static byte[] BuildConnectPacket(string clientId, string username, string password)","sourceCodeStart":179,"sourceCodeEnd":215,"githubUrl":"https://github.com/mgth/LittleBigMouse/blob/7a42f01d47d99d223b8ee33ba4019af82adf1c48/LittleBigMouse.Plugins/LittleBigMouse.Plugin.Vcp.Avalonia/HisenseVidaa/VidaaMqttConnection.cs#L179-L215","documentation":"Thrown by WritePacketAsync when attempting to write an MQTT packet while _stream is null, meaning the connection has not been opened or has already been closed/disposed. The library guards the write with an IOException so callers get a clear 'connection closed' signal instead of a NullReferenceException. Any operation that sends packets (connect handshake, ping loop, command writes) will hit this if the session is not alive.","triggerScenarios":"WritePacketAsync is called by ConnectAsync, PingLoopAsync, or WriteMqttPacketAsync while _stream is null — i.e. writing before OpenMqttAsync completed, after Close/Dispose, or after the read loop detected the TV dropped the connection and cleared _stream.","commonSituations":"Sending a mouse/VCP command after the TV rebooted or the Wi-Fi dropped; a long-lived connection object reused after Dispose; concurrent commands racing with an implicit disconnect; forgetting to call OpenMqttAsync before the first write.","solutions":["Call OpenMqttAsync (which runs ConnectAsync) before sending any packets, and check IsConnected/_connected first if available.","Reopen the connection after a close: wrap sends so that on IOException the connection is re-established and the command retried.","Serialize access: don't dispose/close the connection while writes are in flight; await in-flight commands before closing.","Handle TV-side disconnects (reboot, sleep) by subscribing to the read-loop completion and marking the connection dead instead of reusing it."],"exampleFix":"// before: writes assume the connection is always open\nawait connection.WriteMqttPacketAsync(packet, token);\n// after: ensure/reopen the connection before writing\nif (!connection.IsConnected) await connection.OpenMqttAsync(token);\nawait connection.WriteMqttPacketAsync(packet, token);","handlingStrategy":"validation","validationCode":"// Check connection state before writing\nif (_stream is null || !IsConnected)\n    throw new InvalidOperationException(\"Open the MQTT connection (OpenMqttAsync) before sending packets.\");","typeGuard":"bool CanWrite(VidaaMqttConnection c) => c is { IsConnected: true };","tryCatchPattern":"try { await connection.WriteMqttPacketAsync(packet, token); }\ncatch (IOException e) when (e.Message.Contains(\"connection is closed\"))\n{ await connection.OpenMqttAsync(token); await connection.WriteMqttPacketAsync(packet, token); }","preventionTips":["Always open the connection before the first command and after any close/dispose","Track read-loop completion to mark the connection dead instead of reusing it","Serialize writes with the connection lifetime; never dispose while writes are pending","Wrap command sends in a reconnect-once helper"],"tags":["mqtt","connection-closed","invalid-state","iot"],"backgroundTag":"invalid-state-transition","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"}