tauri-apps / tauri-apps/plugins-workspace
[bug][opener] revealItemInDir panics on Linux: blocking zbus connection inside the async command ('Cannot start a runtime from within a runtime')
- Dominant language
- Rust
- Stars
- 1.8k
- Forks
- 602
- Avg merge
- 4d 14h
- Merged PRs (30d)
- 9
Description
### Describe the bug
On Linux, calling `revealItemInDir` from JS panics the backend with `Cannot start a runtime from within a runtime`, and the JS promise never settles (no rejection reaches the frontend).
Root cause: the plugin's Linux implementation calls `zbus::blocking::Connection::session()` synchronously inside the async `#[tauri::command]` handler, which executes on a tokio runtime worker thread ([`src/reveal_item_in_dir.rs` L206 in 2.5.3](https://github.com/tauri-apps/plugins-workspace/blob/plugins/opener-v2.5.3/plugins/opener/src/reveal_item_in_dir.rs); same code at ~L216 in 2.5.4 — both versions verified affected). When zbus is built with its `tokio` feature (common in Tauri app dep trees), `zbus::utils::block_on` drives the connection future via `tokio::runtime::Runtime::block_on`, which tokio refuses on a worker thread → panic in the command task; the invoke response is never sent.
### Reproduction
1. Tauri v2 app on Linux with `tauri-plugin-opener` 2.5.3 or 2.5.4 registered, zbus resolving with the `tokio` feature (zbus 5.14.0 here).
2. From the frontend: `import { revealItemInDir } from "@tauri-apps/plugin-opener"; await revealItemInDir("/some/existing/file");`
3. Run with `RUST_BACKTRACE=1`: the panic below is printed; no file manager opens; the JS promise stays pending forever.
Observed in a real app (repo is private, but the call site is a one-liner as above); reproduced consistently on every invocation.
### Expected behavior
The file manager opens with the item selected (the underlying D-Bus `org.freedesktop.FileManager1.ShowItems` mechanism works — calling it off-runtime succeeds), and any error rejects the JS promise instead of hanging it.
**Workaround that fixes it** (app-side): wrap the plugin's sync Rust API in a blocking task inside a custom command —
```rust
#[tauri::command]
async fn reveal_in_file_manager(path: String) -> Result<(), String> {
tauri::async_runtime::spawn_blocking(move || tauri_plugin_opener::reveal_item_in_dir(&path))
.await
.map_err(|e| e.to_string())?
.map_err(|e| e.to_string())
}
```
Verified working end-to-end. The same `spawn_blocking` treatment inside the plugin's `reveal_item_in_dir` command (or using async zbus) would fix it for everyone.
### Full `tauri info` output
```text
[⚠] Environment
- OS: Fedora 44.0.0 x86_64 (X64) (KDE on wayland)
✔ webkit2gtk-4.1: 2.52.5
✔ rsvg2: 2.62.3
✔ rustc: 1.97.1 (8bab26f4f 2026-07-14) (Fedora 1.97.1-1.fc44)
✔ cargo: 1.97.1 (c980f4866 2026-06-30) (Fedora 1.97.1-1.fc44)
⚠ rustup: not installed!
⚠ Rust toolchain: couldn't be detected! (distro rust, no rustup)
- node: 24.18.1
- pnpm: 11.1.2
- npm: 12.0.2
- bun: 1.3.14
[-] Packages
- tauri 🦀: 2.10.3, (outdated, latest: 2.11.5)
- tauri-build 🦀: 2.5.6, (outdated, latest: 2.6.3)
- wry 🦀: 0.54.4, (outdated, latest: 0.56.1)
- tao 🦀: 0.34.8, (outdated, latest: 0.37.0)
- @tauri-apps/api ⱼₛ: 2.10.1 (outdated, latest: 2.11.1)
- @tauri-apps/cli ⱼₛ: 2.10.1 (outdated, latest: 2.11.4)
[-] Plugins
- tauri-plugin-opener 🦀: 2.5.3, (outdated, latest: 2.5.4)
- @tauri-apps/plugin-opener ⱼₛ: 2.5.3 (outdated, latest: 2.5.4)
- tauri-plugin-fs 🦀: 2.5.0, (outdated, latest: 2.5.1)
- tauri-plugin-dialog 🦀: 2.7.0, (outdated, latest: 2.7.2)
- tauri-plugin-single-instance 🦀: 2.4.1, (outdated, latest: 2.4.3)
[-] App
- build-type: bundle
- CSP: unset
- frontendDist: ../dist
- devUrl: http://localhost:1420/
- framework: React
- bundler: Vite
```
(2.5.4 was also tested for the panic; the `tauri info` above is from the 2.5.3 lockfile state.)
### Stack trace
```text
thread 'tokio-rt-worker' panicked at tokio-1.52.0/src/runtime/scheduler/multi_thread/mod.rs:91:9:
Cannot start a runtime from within a runtime. This happens because a function (like `block_on`)
attempted to block the current thread while the thread is being used to drive asynchronous tasks.
16: tokio::runtime::context::runtime::enter_runtime::>
at tokio-1.52.0/src/runtime/context/runtime.rs:68:5
17: ::block_on::
at tokio-1.52.0/src/runtime/scheduler/multi_thread/mod.rs:91:9
20: zbus::utils::block_on::
at zbus-5.14.0/src/utils.rs:52:10
21: ::session
at zbus-5.14.0/src/blocking/connection/mod.rs:32:9
22: tauri_plugin_opener::reveal_item_in_dir::imp::reveal_items_in_dir
at tauri-plugin-opener-2.5.3/src/reveal_item_in_dir.rs:206:26
23: tauri_plugin_opener::reveal_item_in_dir::reveal_items_in_dir
at tauri-plugin-opener-2.5.3/src/reveal_item_in_dir.rs:64:12
24: tauri_plugin_opener::commands::reveal_item_in_dir::{closure#0}
at tauri-plugin-opener-2.5.3/src/commands.rs:75:5
```
### Additional context
- Not a duplicate of #3111 (wrong `path` key) or #3304 (Windows UNC paths) — searched open and closed issues/PRs first.
- Because the command task panics, the frontend gets no rejection: from JS this looks like the call silently doing nothing, which makes it easy to misdiagnose as a permissions problem.
-- Claude (on behalf of @superbiche)
Contributor guide
Research direction
Start in src/commands.rs at the reveal_item_in_dir command, then inspect the Linux implementation in src/reveal_item_in_dir.rs around the blocking zbus session call. Reproduce the command on Linux with RUST_BACKTRACE=1 and verify that the file manager opens and the JS promise resolves or rejects instead of leaving the frontend pending.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- desktop-dev
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 76/100