{"record":{"id":"233a9eafcf068d07","repo":"mgth/LittleBigMouse","slug":"channelevent-error","errorCode":null,"errorMessage":"{channelEvent.Error}","messagePattern":"\\{channelEvent\\.Error\\}","errorType":"exception","errorClass":"System.UnauthorizedAccessException","httpStatus":null,"severity":"error","filePath":"LittleBigMouse.Plugins/LittleBigMouse.Plugin.Vcp.Avalonia/SamsungTizen/SamsungTizenClient.cs","lineNumber":57,"sourceCode":"        socket.Options.KeepAliveInterval = TimeSpan.FromSeconds(20);\n\n        // Samsung uses a device-generated certificate. Restricting the connection to the\n        // explicitly selected IPv4 address prevents this exception from becoming a general\n        // trust policy for the application.\n        socket.Options.RemoteCertificateValidationCallback = (_, _, _, _) => true;\n        _socket = socket;\n\n        try\n        {\n            await socket.ConnectAsync(SamsungTizenProtocol.RemoteUri(ipAddress, _token), cancellationToken)\n                .ConfigureAwait(false);\n\n            while (socket.State == WebSocketState.Open)\n            {\n                var message = await ReceiveTextLockedAsync(cancellationToken).ConfigureAwait(false);\n                var channelEvent = SamsungTizenProtocol.ParseChannelEvent(message);\n                if (!string.IsNullOrEmpty(channelEvent.Error))\n                    throw PairingException(channelEvent.Error);\n                if (!channelEvent.Connected) continue;\n\n                if (!string.IsNullOrWhiteSpace(channelEvent.Token)) _token = channelEvent.Token;\n                return;\n            }\n\n            throw new WebSocketException(\"The Samsung display closed the pairing channel.\");\n        }\n        catch (OperationCanceledException)\n        {\n            ResetSocketLocked();\n            throw;\n        }\n        catch (UnauthorizedAccessException)\n        {\n            ResetSocketLocked();\n            throw;\n        }","sourceCodeStart":39,"sourceCodeEnd":75,"githubUrl":"https://github.com/mgth/LittleBigMouse/blob/7a42f01d47d99d223b8ee33ba4019af82adf1c48/LittleBigMouse.Plugins/LittleBigMouse.Plugin.Vcp.Avalonia/SamsungTizen/SamsungTizenClient.cs#L39-L75","documentation":"EnsureConnectedLockedAsync reads JSON WebSocket messages from a Samsung Tizen TV and parses each into a channel event via SamsungTizenProtocol.ParseChannelEvent. When the event carries a non-empty Error field, the device-side pairing/connection failed, and the client surfaces that remote message verbatim via PairingException(channelEvent.Error). The exception text is whatever the TV reported (e.g. 'unrecognized method', 'invalid pin', 'timeout').","triggerScenarios":"Calling EnsureConnectedLockedAsync (via ConnectAsync, SendKeyAsync, or ReopenAsync) while the WebSocket is open and the TV responds to the connect/step payload with {\"error\": ...} — e.g. the user denied the pairing prompt, the PIN/token step timed out, or an unknown method value was sent.","commonSituations":"User dismissed or let the TV's 'Allow' prompt expire; a stale token is rejected after the TV revoked the app; TV firmware changed the protocol method names; calling SendKeyAsync before pairing completed.","solutions":["Read the embedded Error text (it is the exception message) and act on it: retry ConnectAsync and accept the on-screen Allow prompt within the timeout.","Delete the stored token and re-pair from scratch: reset _token / clear the saved SamsungTizen configuration so a fresh PIN prompt is issued.","If the error is about an unrecognized method, update SamsungTizenProtocol step payloads to match the current Tizen firmware's expected step/method names.","Ensure SendKeyAsync is only called after a successful EnsureConnectedLockedAsync (channelEvent.Connected)."],"exampleFix":"// before\nawait client.SendKeyAsync(\"KEY_POWER\"); // throws PairingException(\"unrecognized method 800.unrecognized\")\n// after\ntry { await client.EnsureConnectedLockedAsync(ct); await client.SendKeyAsync(\"KEY_POWER\"); }\ncatch (Exception e) when (e.Message.Contains(\"unrecognized\")) {\n    client.ResetToken();          // discard stale token\n    await client.ConnectAsync(ct); // re-pair, accept prompt on TV\n}","handlingStrategy":"try-catch","validationCode":"// track token freshness yourself\nif (string.IsNullOrEmpty(_token) && tokenRejectedAt > DateTimeOffset.Now.AddMinutes(-5))\n    throw new InvalidOperationException(\"Tizen pairing recently failed; clear token and re-pair before sending keys.\");","typeGuard":null,"tryCatchPattern":"try { await client.EnsureConnectedLockedAsync(ct); }\ncatch (Exception e) when (e.Message.Contains(\"unrecognized\") || e.Message.Contains(\"invalid\")) {\n    _token = null;              // discard stale token\n    await client.ConnectAsync(ct); // full re-pair; user must accept TV prompt\n}","preventionTips":["Always surface the on-screen 'Allow' prompt requirement to the user with a countdown matching the TV timeout.","Purge stored tokens whenever pairing fails or the TV is power-cycled/re-paired.","Log the raw channel event JSON so protocol/method mismatches after firmware updates are diagnosable.","Gate SendKeyAsync behind a successful ConnectAsync check."],"tags":["websocket","samsung","tizen","pairing","smart-tv"],"backgroundTag":"unexpected-api-response-shape","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"}