Docs Reference
Error handling
How LumaSync recovers from render faults — the global ErrorBoundary, the fallback card, the actions available from it, and the macOS lifecycle shutdown path.
From v1.4, LumaSync wraps every React root with a global ErrorBoundary. When a render fault bubbles out of the component tree, you get a localised fallback card — not a blank tray window, not a silent crash. The app keeps running; only the broken panel is replaced with the card.
The fallback card
Shows:
- A short, localised headline (“LumaSync ran into a problem rendering this panel.”)
- The underlying error message (not the stack trace)
- An anonymised fingerprint of the error, used to correlate with the log file
Three actions sit at the bottom of the card:
- Show logs — opens the platform log directory via
open_log_dir. The full stack trace sits in the most recent log file, correlated by the card’s fingerprint. See Notifications →open_log_dir. - Restart — terminates and relaunches the app via
tauri-plugin-process. State in~/.config/lumasync/app.jsonpersists across restart; in-memory session data (current mode, frame queue) is discarded. - Copy error — copies the error message + fingerprint to the clipboard, ready to paste into a GitHub issue or Discussion thread. Does not copy your config, credentials, or the log body — those stay on disk.
What ErrorBoundary catches
- Render-time exceptions in React components (the common case)
- Effect-callback exceptions that synchronously propagate during render
- Lifecycle errors in class components (none ship today, but the boundary handles them anyway)
What it does NOT catch
- Backend worker panics — the Rust / Tauri side. Those are logged by the Rust
tracinglayer and surface as a different UI state: the pipeline halts, status pills go red, no fallback card appears. Check the log file for thepanicline. - Unhandled promise rejections outside React’s lifecycle — a background fetch that rejects without a
.catchlands in the log but does not trip the boundary. - WebView hard crashes (rare) — those terminate the Tauri window entirely; macOS / Windows surface an OS-level crash dialog.
Filing a good issue
If the fallback card appears, attach:
- The Copy error clipboard contents (message + fingerprint)
- The most recent log file from Show logs (review first — it contains your bridge IP and local paths)
- What you were doing when it fired (opened Settings, switched modes, etc.)
Together those three let a maintainer reproduce in the dev console without asking follow-up questions.
macOS lifecycle hardening (v1.5.2)
The macOS shutdown path was previously fragile: Cmd+Q, the tray Quit menu, and Ctrl+C in dev each had their own teardown logic, with subtle ordering differences that could leak file descriptors, the single-instance lock socket, or the Hue DTLS sender thread.
From v1.5.2 all three paths converge on a single kick_off_shutdown_and_die Rust function gated by an atomic SHUTDOWN_FIRED flag. Two follow-ups landed alongside the unification:
- The watchdog’s
std::process::exit(0)previously bypassed Tauri plugindestroy()callbacks, which lefttauri-plugin-single-instance’s/tmp/com_lumasync_app_si.socksocket on disk. The next dev launch detected the stale socket and exited within ~50 ms. The plugin is now#[cfg(not(debug_assertions))]-gated to release builds only, so dev launches don’t touch the socket and don’t leak it. stop_hue_streamcould block for up to 8 s under a worst-case combination ofreqwesttimeout (5 s) plus a DTLS sender Condvar (3 s), blowing through the 4 s watchdog budget. The call is now detached onto a worker thread and abandoned after 1.5 s — safe because the bridge times out the entertainment session server-side regardless.
End result: Cmd+Q closes the app cleanly within the watchdog budget every time, and dev rebuilds no longer fail with single-instance-lock hangs.
Related
- Telemetry — logs directory and rotation
- Notifications —
open_log_dirand OS toasts - USB troubleshooting — device-level errors take a different path than ErrorBoundary
- Hue troubleshooting — the
HUE_STREAM_NOT_READY_ACTIVE_STREAMER403 retired in v1.5.2