Skip to content

fix(tauri): prevent CEF init panic on second launch via single-instance plugin#1510

Merged
senamakel merged 2 commits into
tinyhumansai:mainfrom
senamakel:fix/cef-init-single-instance
May 12, 2026
Merged

fix(tauri): prevent CEF init panic on second launch via single-instance plugin#1510
senamakel merged 2 commits into
tinyhumansai:mainfrom
senamakel:fix/cef-init-single-instance

Conversation

@senamakel
Copy link
Copy Markdown
Member

@senamakel senamakel commented May 12, 2026

Summary

Problem

Sentry OPENHUMAN-TAURI-A — 442 fatal panics across 8 days, Win10/11 + Linux (Kali, Debian, CachyOS), every recent release (0.53.13 → 0.53.22). 0 users impacted because the panic is pre-auth.

Root cause: app/src-tauri/vendor/tauri-cef/.../lib.rs:2071 does assert_eq!(cef::initialize(...), 1). The shell registered no tauri-plugin-single-instance, so launching a second instance (auto-start, double-click, deep-link reopen) raced into CefRuntime::init while the primary still held the CEF cache lock, cef::initialize returned 0, and the assert panicked. The cross-OS, cross-release, pre-auth pattern matches cache-lock contention, not a code regression in any single release.

Solution

Two layers, both needed:

  1. Primary fix — register tauri_plugin_single_instance::init(...) as the first plugin in run() (before tauri_plugin_opener, deep_link, etc.). The plugin acquires a per-identifier lock before any other plugin setup. A secondary launch hands argv/cwd to the primary via the callback (which logs and focuses the main window via the existing show_main_window helper) and exits before Builder::build() reaches CEF init.
  2. Defense in depth — submodule bump replaces the assert with a panic that includes the actual return code and cache_path, so any remaining CEF init failure (corrupt cache, missing helpers, sandbox denied) lands in Sentry with actionable context instead of assertion left == right.

Plugin is pinned to the same plugins-workspace rev (c6561ab6…) as the other Tauri plugins via the existing [patch.crates-io] block. Submodule PR: tinyhumansai/tauri-cef#13.

Submission Checklist

  • N/A: behavior under contention is environment-dependent (race between two processes for a CEF cache lock); not feasible to assert in a Vitest/cargo-test harness. Smoke-tested via cargo check --manifest-path app/src-tauri/Cargo.toml.
  • N/A: change is in Rust shell startup code; coverage gate applies to Vitest + cargo-llvm-cov, neither of which exercise Builder::build() / CefRuntime::init paths.
  • N/A: behaviour-only change; no feature row added/removed in the coverage matrix.
  • N/A: no matrix feature IDs affected.
  • No new external network dependencies introduced.
  • N/A: not a release-cut surface; affects pre-auth startup robustness only.
  • Linked issue: Fixes OPENHUMAN-TAURI-A (Sentry) — auto-resolves the Sentry issue on merge.

Impact

  • Platforms: desktop (Windows, macOS, Linux). No mobile/web/CLI impact.
  • Runtime: a second invocation of the binary now exits cleanly after handing its argv to the primary, instead of crashing. The primary window comes to focus.
  • Compat: tauri-plugin-single-instance uses a named mutex on Windows, a Unix domain socket on macOS, and dbus on Linux — all per tauri.conf.json identifier (com.openhuman.app). No collisions with existing infrastructure.
  • Security: no new attack surface; the plugin's IPC channel is per-user and identifier-scoped.

Related


AI Authored PR Metadata (required for Codex/Linear PRs)

Linear Issue

  • Key: N/A
  • URL: N/A (Sentry-only)

Commit & Branch

  • Branch: fix/cef-init-single-instance
  • Commit SHA: 0e33e619

Validation Run

  • N/A: no frontend changes (Rust/Tauri-only PR).
  • N/A: no frontend changes.
  • N/A: behavior under multi-process contention not unit-testable.
  • cargo check --manifest-path app/src-tauri/Cargo.toml — clean (pre-existing warnings only).
  • cargo fmt on the two touched Rust files.

Validation Blocked

  • command: N/A
  • error: N/A
  • impact: N/A

Behavior Changes

  • Intended behavior change: second app launch focuses the existing primary instead of crashing.
  • User-visible effect: users who double-click the app or have auto-start enabled no longer see a fatal crash; the existing window comes forward.

Parity Contract

  • Legacy behavior preserved: primary-instance startup unchanged; only the secondary path is new (and the secondary path was previously "panic", so any well-defined behavior is strictly an improvement).
  • Guard/fallback/dispatch parity checks: deep-link plugin still handles deep-link payloads; the single-instance callback only logs + focuses, leaving payload processing to tauri-plugin-deep-link.

Duplicate / Superseded PR Handling

  • Duplicate PR(s): none.
  • Canonical PR: this one.
  • Resolution: N/A.

Summary by CodeRabbit

  • New Features

    • App now enforces single-instance behavior: launching a second instance will focus the existing window instead of creating a duplicate.
  • Chores

    • Pinned and aligned native plugin revisions and updated vendored components to improve startup robustness and prevent race conditions during initialization.

Review Change Stack

…ce plugin

The Tauri shell had no single-instance guard, so launching a second
instance (auto-start, double-click, deep-link reopen, …) raced into
`CefRuntime::init` while the primary still held the CEF cache lock,
`cef::initialize` returned 0, and the vendored runtime's
`assert_eq!(..., 1)` panicked. This fires across Win10/11 + multiple
Linux distros on every recent release (Sentry OPENHUMAN-TAURI-A,
442 events over 8 days, 0 users impacted because the panic is pre-auth).

Changes:
- Add `tauri-plugin-single-instance` (pinned to the same
  plugins-workspace rev as the other plugins) and register it as the
  *first* plugin in `run()`, so a secondary launch focuses the primary
  via the existing `show_main_window` helper and exits before
  `Builder::build()` reaches CEF init.
- Bump the `vendor/tauri-cef` submodule pointer to pick up
  `tinyhumansai/tauri-cef#13`, which replaces the opaque
  `assertion left == right` with a panic that logs the actual return
  code and `cache_path` — defense in depth for any other CEF init
  failure mode.

Fixes OPENHUMAN-TAURI-A
@senamakel senamakel requested a review from a team May 12, 2026 02:05
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 12, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: dcbfb175-a71b-4ba2-a80b-71ab9183fe8c

📥 Commits

Reviewing files that changed from the base of the PR and between 0e33e61 and 1cd041c.

📒 Files selected for processing (1)
  • app/src-tauri/src/lib.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • app/src-tauri/src/lib.rs

📝 Walkthrough

Walkthrough

This pull request integrates the tauri-plugin-single-instance plugin to enforce single-instance execution and prevent concurrent CEF initialization. The plugin dependency is added to Cargo.toml and pinned to a specific revision, then wired into the Tauri AppBuilder with a callback that focuses the primary window when secondary launch attempts occur. The CEF submodule is also updated.

Changes

Single-instance protection feature

Layer / File(s) Summary
Plugin dependency and patch configuration
app/src-tauri/Cargo.toml
tauri-plugin-single-instance = "2" is added to dependencies with inline documentation explaining the CEF race prevention role. The plugin is pinned in [patch.crates-io] to a specific plugins-workspace git revision.
Plugin wiring in application startup
app/src-tauri/src/lib.rs
tauri_plugin_single_instance::init is inserted into the AppBuilder chain with a callback that logs secondary launches and calls show_main_window(app) to focus the primary window.
CEF vendored submodule update
app/src-tauri/vendor/tauri-cef
The tauri-cef submodule pointer is updated to a new commit hash.

Sequence Diagram

sequenceDiagram
  participant SecondaryProcess as SecondaryLaunch
  participant Plugin as tauri_plugin_single_instance
  participant App as TauriApp
  participant Window as MainWindow

  SecondaryProcess->>Plugin: notify_secondary_launch()
  Plugin->>App: invoke_callback(redacted_launch_info)
  App->>Window: show_main_window()
Loading

🎯 2 (Simple) | ⏱️ ~8 minutes

Possibly related PRs:

A rabbit hops to ensure single bounds,
One instance per launch, no races unwound,
CEF sits safely while plugin stands guard—
When newcomers arrive, they're redirected toward
The first window shown, \🐰 job done, not too hard!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: adding a single-instance plugin to prevent CEF initialization panic on secondary app launches, which is the core objective of this PR.
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.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


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

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@app/src-tauri/src/lib.rs`:
- Around line 1377-1379: The log call in the single-instance handler currently
prints raw args and cwd via the log::info! invocation ("[single-instance]
secondary launch detected, focusing primary (argv={args:?}, cwd={cwd})"), which
can leak tokens; change it to avoid printing raw argv/cwd—e.g., log only safe
metadata such as args.len() and a redacted or canonicalized cwd (or a boolean
indicating presence), or sanitize/deep-link-specific values before logging;
update the log::info! call so it emits something like argv_count and cwd_safe
(no raw contents) instead of printing {args:?} and {cwd}.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: dbbea93b-e95f-41ae-8dbf-9242783b99c6

📥 Commits

Reviewing files that changed from the base of the PR and between fd0ac9c and 0e33e61.

⛔ Files ignored due to path filters (1)
  • app/src-tauri/Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (3)
  • app/src-tauri/Cargo.toml
  • app/src-tauri/src/lib.rs
  • app/src-tauri/vendor/tauri-cef

Comment thread app/src-tauri/src/lib.rs
…kage

CodeRabbit on tinyhumansai#1510: the single-instance secondary-launch handler logged
raw `args` and `cwd`. Deep-link argv frequently carries OAuth codes /
magic-link tokens, which would leak into desktop logs and Sentry
breadcrumbs.

Log only argc and a boolean for cwd presence.
@senamakel senamakel merged commit e3749a0 into tinyhumansai:main May 12, 2026
20 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.

1 participant