Skip to content

fix(ble): don't throw from long-session health snapshot on Linux - #834

Merged
rinchen merged 1 commit into
Colorado-Mesh:mainfrom
WB3IHY:fix/noble-long-session-snapshot-linux
Aug 10, 2026
Merged

fix(ble): don't throw from long-session health snapshot on Linux#834
rinchen merged 1 commit into
Colorado-Mesh:mainfrom
WB3IHY:fix/noble-long-session-snapshot-linux

Conversation

@WB3IHY

@WB3IHY WB3IHY commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

Problem

On Linux, after mesh-client had been running continuously for a bit over 24 hours, users could hit an "Mesh-Client — Unexpected Error" dialog:

Unknown noble session: meshtastic
  at Fu.getSession (.../dist-electron/main/index.js:825:57375)
  at Fu.getLongSessionHealthSnapshot (.../dist-electron/main/index.js:825:62421)
  at Timeout._onTimeout (.../dist-electron/main/index.js:988:18724)

Diagnosed from a user-supplied support bundle: the crash fired at exactly 24h 9s of main-process uptime, matching the hourly long-session health timer in src/main/index.ts that only executes its body once process.uptime() crosses the 24h threshold.

Root cause

NobleBleManager.getLongSessionHealthSnapshot() called the throwing getSession() unconditionally for both the meshtastic and meshcore sessions. On Linux, Noble is never initialized (Web Bluetooth is used in the renderer instead) — the constructor returns early before populating the sessions map, so it stays empty for the app's entire lifetime. The first time the 24h-gated health-log timer actually ran its body, the lookup threw, and since it's an uncaught exception in the main process, the global uncaughtException handler surfaced it as a user-facing error dialog (the app itself did not crash/quit — traffic continued normally afterward).

Fix

Guard the session lookup the same way disconnectAll() and stopAllScanning() already guard for Linux, returning a benign "not initialized" snapshot instead of throwing. Extracted the shared sessions.size === 0 check (which was about to be triplicated) into one private isLinuxNotInitialized() helper used by all three call sites.

Testing

  • New regression tests in noble-ble-manager.test.ts (source-contract style, matching this file's established pattern for testing a class that wraps the native @stoprocent/noble module) verifying the guard is present and that no inline sessions.size === 0 checks remain outside the shared helper.
  • pnpm run typecheck, pnpm exec eslint on changed files, and the full main Vitest project (200 files / 2223 tests) all pass.
  • Pre-commit hook ran clean (security scanners, i18n, license check, staged-related Vitest — including the adjacent noble-ble-manager.behavior.test.ts, 53 tests).

Summary by CodeRabbit

  • Bug Fixes

    • Improved Bluetooth behavior on Linux when the Bluetooth subsystem is not initialized.
    • Health checks now report a safe disconnected state instead of failing.
    • Scanning and disconnect actions avoid unavailable cleanup operations in this state.
  • Tests

    • Added regression coverage for Linux Bluetooth initialization scenarios.

getLongSessionHealthSnapshot() called the throwing getSession() unconditionally.
On Linux, Noble is never initialized (Web Bluetooth is used in the renderer
instead), so the sessions map stays empty for the app's whole lifetime. Once
the hourly main-process health-log timer's 24h uptime gate opened, the first
tick threw an uncaught "Unknown noble session: meshtastic" in the main
process, surfaced to the user as the "Mesh-Client — Unexpected Error" dialog
after about a day of uptime.

Guard sessionDetail() the same way disconnectAll() and stopAllScanning()
already guard for Linux, returning a benign not-initialized snapshot instead
of throwing. Extract the shared isLinuxNotInitialized() check that guard
duplicated across all three call sites into one private helper.
@coderabbitai

coderabbitai Bot commented Aug 10, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: QUIET

Plan: Pro Plus

Run ID: cb210ea6-ad7f-426e-a81e-51ccf927f0eb

📥 Commits

Reviewing files that changed from the base of the PR and between 8a6d169 and 17a635d.

📒 Files selected for processing (2)
  • src/main/noble-ble-manager.test.ts
  • src/main/noble-ble-manager.ts

📝 Walkthrough

Walkthrough

The Noble BLE manager centralizes detection of uninitialized Linux sessions. Health snapshots return disconnected details without accessing unavailable session state, and scanning shutdown and disconnection cleanup use the shared check. Regression tests cover these paths.

Changes

Linux Noble initialization handling

Layer / File(s) Summary
Shared initialization check
src/main/noble-ble-manager.ts
Adds isLinuxNotInitialized() to detect Linux environments without Noble sessions.
Health and teardown integration
src/main/noble-ble-manager.ts, src/main/noble-ble-manager.test.ts
Health snapshots avoid getSession() and return zeroed disconnected details when Noble is uninitialized. stopAllScanning() and disconnectAll() use the shared check. Regression tests cover these behaviors.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related PRs

Suggested reviewers: rinchen

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main fix: preventing Linux long-session health snapshots from throwing errors.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@rinchen
rinchen merged commit 8d0be83 into Colorado-Mesh:main Aug 10, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants