Xibo for Windows v4 R407.2 — NullReferenceException in GetActions() when handling Webhook-triggered Actions

Xibo for Windows v4 R407.2 — NullReferenceException in GetActions() when handling Webhook-triggered Actions

Summary

The embedded web server’s webhook trigger endpoint (/trigger?trigger=<code>) reliably crashes the action-handling code path with an unhandled NullReferenceException inside MainWindow.GetActions(), called from MainWindow.HandleActionTrigger(). This happens both with a full layout (7 Actions) and with a minimal reproduction (a single Action). The HTTP client sees the connection close mid-request without any response.

Environment

  • Xibo CMS: self-hosted on Docker (Hetzner) — version 4.4.4

  • Player: Xibo for Windows, v4 R407.2

  • OS: Windows 11 Pro, Mini-PC (Dell OptiPlex Micro / Lenovo ThinkCentre class device)

  • Display profile: Embedded Web Server Port 9696, bound on [::1] (IPv6 loopback) only — confirmed via netstat, no IPv4 listener present

  • Watchdog: enabled (default)

Steps to reproduce

  1. Layout, portrait 1080×1920, one full-screen Region (REG_CONTENT).

  2. Region’s normal timeline: one widget (Splash/idle content).

  3. Interactive Mode → ON, to expose the Drawer.

  4. Action configured on the Layout itself (not on a Widget — confirmed via the “Auslöser”/Trigger Source field showing the Layout name):

    • Action type: Navigate to Widget

    • Trigger type: Webhook

    • Trigger code: SLOT1

    • Target: Region (Zone)

    • Widget to Load: created inline via the “Create Widget” button inside the Action dialog (this CMS build does not let you pick a pre-existing Drawer widget from a list — it only offers inline creation)

  5. Layout published, scheduled “Always” on the Display’s Display Group.

  6. From a process running locally on the same machine as the Player, send:

    POST http://[::1]:9696/trigger?trigger=SLOT1
    
    
  7. Observed: the TCP connection is accepted, then closed by the Player without sending any HTTP response (Remote end closed connection without response on the client side). The on-screen content never changes.

Minimal reproduction (rules out complexity as the cause)

To rule out that this was related to the complexity of our production layout (7 Actions, 6 Embedded HTML Drawer widgets), we cloned the layout and stripped it down to:

  • 1 Region

  • 2 Actions only: SLOT1 → Widget, RESET → Widget (both inline-created Text widgets)

Result: identical crash, identical error. This confirms the issue is not related to the number of Actions or Widgets — a single Action is enough to trigger it.

Error captured in CMS Display Log

Unhandled Exception: Der Objektverweis wurde nicht auf eine Objektinstanz festgelegt.
(= Object reference not set to an instance of an object / NullReferenceException)

   at XiboClient.MainWindow.GetActions() in ...\MainWindow.xaml.cs:line 1176
   at XiboClient.MainWindow.HandleActionTrigger(String triggerType, String triggerCode, Int32 sourceId, Point point) in ...\MainWindow.xaml.cs:line 1273
   at XiboClient.MainWindow.MouseInterceptor_MouseClickEvent(Point point) in ...\MainWindow.xaml.cs:line 262
   at XiboClient.Logic.MouseInterceptor.HookCallback(Int32 nCode, IntPtr wParam, IntPtr lParam) in ...\MouseInterceptor.cs:line 94

Note: this particular captured instance was triggered via a mouse click (touch trigger type) rather than the webhook path, but it goes through the exact same HandleActionTriggerGetActions() call chain that our webhook POST uses — so both trigger types appear to hit the same underlying bug.

This matches an earlier community report with the identical stack trace (different line number): Client problems (windows log file)

Each crash is also accompanied by repeated Watchdog log entries ([Watcher] Watchdog) alternating between “Too many active processes” and “No active processes”, consistent with the Player process crashing and being restarted in a loop.

What we’ve ruled out

  • Network/firewall: confirmed the embedded web server accepts the TCP connection (visible in netstat, and via the differing error signature compared to a genuinely closed port).

  • IPv4 vs IPv6: not the cause — same crash signature on the correct IPv6 loopback address.

  • System proxy interference: ruled out, no proxy configured on the machine.

  • RF/NFC tag bounce on our middleware side: ruled out via software debouncing — single, clean trigger events still crash the Player.

  • Layout/Action complexity: ruled out via the minimal 1-Action reproduction above.

  • CMS-side XMR “Trigger webhook” push: inconclusive — this specific Display isn’t currently configured/ready to receive XMR push commands (“nicht konfiguriert oder bereit, Push-Befehle über XMR zu empfangen”), so we couldn’t test whether that code path hits the same bug. Not a blocker for us either way, since our production design intentionally avoids the CMS/XMR path for this feature (local-only, millisecond-latency trigger).

Request

Has anyone seen this NullReferenceException in GetActions() on R407.x, and is there a known fix or workaround? Happy to provide the full CMS log export and exact Action JSON if useful.


Update — minimal reproduction without external hardware, plus log evidence

Two additions to the report above.

1. Minimal reproduction (no scripts, no NFC hardware)

The failure reproduces with a single curl call from the player machine itself, against the player’s local EmbeddedServer:

curl.exe -X POST "http://[::1]:9696/trigger?trigger=SLOT1" -v

Result: connection accepted, request sent in full (Request completely sent off), then:

curl: (52) Empty reply from server

The player writes no HTTP response and performs no layout change. netstat confirms the EmbeddedServer is listening on [::1]:9696 (IPv6 localhost) at the time of the call. Reproducible on every attempt, with both Navigate to Widget and Navigate to Layout action types, and whether the trigger arrives via Webhook or Touch/Click — indicating the failure occurs before action-type dispatch.

Minimal case: single layout, single text widget, single action, single trigger code. Layout complexity and action count are ruled out.

2. Log evidence (Audit level)

With Audit logging enabled, no error is written at the moment of the trigger — the trigger leaves no trace in the log at all, despite full Audit coverage of all other player activity (schedule ticks, media changes, etc.). The only related error appears at player shutdown, where the runtime surfaces a previously-swallowed task exception:

Error: Unhandled Exception: UnobservedTaskException: 
(a task's exceptions were not observed; re-thrown by the finalizer thread)
Error: Stack Trace:

Note the empty stack trace. This strongly suggests the action-trigger handler runs as a fire-and-forget async task whose exception is never awaited or caught: it silently closes the HTTP connection (producing the Empty reply above), logs nothing at trigger time, and only surfaces — without a usable trace — when the finalizer runs at shutdown.

It is also worth noting the log contains only EmbeddedServer - Server Stopped entries, never a corresponding Started/Listening entry, across multiple player runs.

(In an earlier diagnostic session this defect presented as a NullReferenceException in GetActions(). I was not able to re-capture that verbatim trace under Audit logging in the current run — the current evidence is the UnobservedTaskException above, which is consistent with the same underlying cause: an unobserved exception in the asynchronous action-handling path.)

3. Recurring locus

The layout-bound interactive-action path has prior history — GitHub issue #222 (2021, “Interactive: Layout Touch/Click Action not triggering”) was closed as resolved but reported by users as incomplete. The current crash may be a regression in the same component.

Happy to provide the full Audit log, a layout export, or to test a patched build.

Additionally tested on a separate Windows 10 machine (fresh player install, same CMS, minimal single-action layout): identical curl: (52) Empty reply from server. This rules out OS version (Windows 10 vs 11) as a factor — the defect is reproducible across Windows versions.