From e3a78f335a4f3bc520553b76cae192084e4474c8 Mon Sep 17 00:00:00 2001 From: Z User Date: Sat, 30 May 2026 19:59:54 +0000 Subject: [PATCH] Add comprehensive Tauri 2.0 error resolution guide - tauri2-guide/error-resolution-guide.md: ~1700 lines covering 18 error categories with 65+ specific errors, exact messages, root causes, and working solutions: Category A: Rust compilation errors (Cargo build, version mismatch, edition, missing tools, windows crate hangs) Category B: v1->v2 migration compile errors (api removals, type renames, feature changes, JS import paths) Category C: Async command & thread safety errors (lifetime issues, Mutex/RwLock Send bounds, non-Send types) Category D: Configuration errors (v1 keys in v2 config, allowlist, frontendDist) Category E: Capabilities & permission errors (plugin not allowed, scope denied, shell scope) Category F: Plugin integration errors (registration, version conflicts) Category G: IPC/command runtime errors (command not found, serialize issues) Category H: Webview & window errors (WebView2, blank screens, unstable feature) Category I: Event system errors (race conditions, cross-window events) Category J: CSP errors (ipc.localhost, CSS-in-JS) Category K: Frontend integration (Vite, Next.js, SvelteKit issues) Category L: WebSocket errors (broken pipe, unstable connections) Category M: Path & asset protocol errors (403 forbidden, traversal) Category N: Shell & sidecar errors (binary not found, naming) Category O: Mobile build errors (iOS code signing, Android NDK, targets) Category P: Platform-specific build errors (Linux deps, ICNS, linuxdeploy) Category Q: Panics & runtime crashes Category R: Error handling best practices Plus a quick-reference table of the 25 most common errors. --- tauri2-guide/error-resolution-guide.md | 1817 ++++++++++++++++++++++++ 1 file changed, 1817 insertions(+) create mode 100644 tauri2-guide/error-resolution-guide.md diff --git a/tauri2-guide/error-resolution-guide.md b/tauri2-guide/error-resolution-guide.md new file mode 100644 index 0000000..d0c15e1 --- /dev/null +++ b/tauri2-guide/error-resolution-guide.md @@ -0,0 +1,1817 @@ +# Tauri 2.0 Error Resolution Guide + +> **Version**: 2.0 | **Last Updated**: 2026-05-31 +> **Official Docs**: https://v2.tauri.app +> +> This guide catalogs every known class of error in Tauri 2.0 development — Rust compilation errors, Cargo/dependency failures, runtime panics, permission errors, frontend integration issues, mobile build failures, and platform-specific problems. Each error includes the exact message, root cause, and working solution. + +--- + +## Table of Contents + +1. [Category A: Rust Compilation Errors (Cargo Build)](#category-a-rust-compilation-errors-cargo-build) +2. [Category B: v1→v2 Migration Compile Errors](#category-b-v1v2-migration-compile-errors) +3. [Category C: Async Command & Thread Safety Errors](#category-c-async-command--thread-safety-errors) +4. [Category D: Configuration (`tauri.conf.json`) Errors](#category-d-configuration-tauriconfjson-errors) +5. [Category E: Capabilities & Permission Errors](#category-e-capabilities--permission-errors) +6. [Category F: Plugin Integration Errors](#category-f-plugin-integration-errors) +7. [Category G: IPC / Command Runtime Errors](#category-g-ipc--command-runtime-errors) +8. [Category H: Webview & Window Runtime Errors](#category-h-webview--window-runtime-errors) +9. [Category I: Event System Errors](#category-i-event-system-errors) +10. [Category J: Content Security Policy (CSP) Errors](#category-j-content-security-policy-csp-errors) +11. [Category K: Frontend Integration Errors (Vite / Next.js / SvelteKit)](#category-k-frontend-integration-errors-vite--nextjs--sveltekit) +12. [Category L: WebSocket Errors](#category-l-websocket-errors) +13. [Category M: Path & Asset Protocol Errors](#category-m-path--asset-protocol-errors) +14. [Category N: Shell & Sidecar Errors](#category-n-shell--sidecar-errors) +15. [Category O: Mobile Build Errors (iOS & Android)](#category-o-mobile-build-errors-ios--android) +16. [Category P: Platform-Specific Build Errors](#category-p-platform-specific-build-errors) +17. [Category Q: Panics & Runtime Crashes](#category-q-panics--runtime-crashes) +18. [Category R: Error Handling Best Practices](#category-r-error-handling-best-practices) +19. [Quick-Reference: Top 25 Most Common Errors](#quick-reference-top-25-most-common-errors) + +--- + +## Category A: Rust Compilation Errors (Cargo Build) + +### A1. `tauri` and `tauri-build` Version Mismatch + +**Error:** +``` +failed to get cargo metadata: cargo metadata command exited with a non zero exit code: error: failed to parse manifest +``` + +**Cause:** Mixed v1 and v2 dependencies in `Cargo.toml`. The `tauri` and `tauri-build` crate versions don't match, or old plugin dependencies remain from v1. + +**Solution:** Ensure all `tauri-*` dependencies are on v2. Run `cargo update` in `src-tauri/`: +```toml +[build-dependencies] +tauri-build = { version = "2", features = [] } + +[dependencies] +tauri = { version = "2", features = [] } +tauri-plugin-opener = "2" # NOT "1" +``` +Then: `cd src-tauri && cargo update` + +--- + +### A2. Rust Edition 2024 Incompatibility + +**Error:** +Cargo.toml resolution errors or crate compilation failures with no clear error message. + +**Cause:** Tauri 2.0 is **incompatible** with Rust Edition 2024 due to a dependency on the `cargo_toml` crate (specified as `^0.19`). + +**Solution:** Use `edition = "2021"` in `Cargo.toml` — do NOT switch to edition 2024: +```toml +[package] +edition = "2021" # Required — edition 2024 will NOT work +``` + +--- + +### A3. Missing `#[lib]` Section in Cargo.toml + +**Error:** +``` +error: `src-tauri/src/lib.rs` not found +``` +or linker errors on mobile platforms. + +**Cause:** Tauri 2.0 requires a `lib.rs` entry-point. The `Cargo.toml` must declare a `[lib]` section with the correct crate types for mobile support. + +**Solution:** Add to `Cargo.toml`: +```toml +[lib] +name = "my_app_lib" +crate-type = ["staticlib", "cdylib", "rlib"] +``` +Create `src-tauri/src/lib.rs` with your core logic in `pub fn run()`, and a minimal `main.rs` that calls `my_app_lib::run()`. + +--- + +### A4. `windres` Not Found (Windows) + +**Error:** +``` +error: Couldn't execute windres to compile Windows resource file (.rc) +``` + +**Cause:** Missing the Windows resource compiler, which is part of the MinGW or MSVC build tools. + +**Solution:** Install Visual Studio Build Tools with the "Desktop development with C++" workload. Ensure `rc.exe` and `windres` are on your system PATH. Alternatively, install the full Visual Studio IDE. + +--- + +### A5. `strip` Fails on Linux + +**Error:** +``` +error: Calling strip on library ... failed +``` + +**Cause:** Incompatible or missing `strip` binary on Linux (particularly Arch-based distros). + +**Solution:** Install GNU binutils: +```bash +sudo pacman -S binutils # Arch +sudo apt install binutils # Debian/Ubuntu +sudo dnf install binutils # Fedora +``` + +--- + +### A6. Windows `windows` Crate Compilation Hangs + +**Error:** Build hangs silently at "Compiling windows v0.61.x" with no progress. + +**Cause:** Two common causes: +1. **Trend Micro** (or similar antivirus) "Unauthorized Change Prevention" blocking `rustc.exe` +2. Feature unification causing hundreds of Win32 API features to activate, making compilation extremely slow + +**Solution:** +1. Temporarily disable Trend Micro or add an exception for the project directory +2. Reduce parallel jobs: `set CARGO_BUILD_JOBS=1` +3. Optimize dev build for the `windows` crate: +```toml +[profile.dev.package.windows] +opt-level = 1 +``` + +--- + +### A7. Build Terminates Silently Mid-Build + +**Error:** `cargo build` stops at ~50% with no error output. + +**Cause:** Antivirus interference, out-of-memory, or corrupted build cache. + +**Solution:** +1. Clear build cache: `cd src-tauri && cargo clean` +2. Temporarily disable antivirus +3. Reduce parallel jobs: `CARGO_BUILD_JOBS=1` +4. Check disk space and available RAM + +--- + +### A8. `STATUS_ACCESS_VIOLATION` During Compilation (Windows) + +**Error:** +``` +STATUS_ACCESS_VIOLATION +``` +Segfault during the build process. + +**Cause:** Corrupted toolchain, incompatible library version, or memory issue. + +**Solution:** +1. Update Rust toolchain: `rustup update` +2. Clean and rebuild: `cd src-tauri && cargo clean && cargo build` +3. If persistent, reinstall Rust: `rustup self uninstall && rustup-init` + +--- + +## Category B: v1→v2 Migration Compile Errors + +### B1. `tauri::api` Module Removed + +**Error:** +``` +error[E0432]: unresolved import `tauri::api` +``` +or `error[E0412]: cannot find module 'api' in 'tauri'` + +**Cause:** Tauri 2.0 completely removed `tauri::api`. Every sub-module was moved to plugins. + +**Solution:** Replace each sub-module: +```rust +// ❌ v1 — all of these are REMOVED +use tauri::api::dialog; +use tauri::api::http; +use tauri::api::fs; +use tauri::api::path; +use tauri::api::process::Command; +use tauri::api::shell; +use tauri::api::version; + +// ✅ v2 — use plugins or std +// dialog → tauri-plugin-dialog +// http → tauri-plugin-http +// fs → std::fs (Rust) or tauri-plugin-fs (JS) +// path → tauri::Manager::path() +// process/shell → tauri-plugin-shell +// version → semver crate +``` + +--- + +### B2. `Window` Type Renamed to `WebviewWindow` + +**Error:** +``` +error[E0412]: cannot find type `Window` in `tauri` +error[E0433]: failed to resolve: use of undeclared type `Window` +``` + +**Cause:** The `Window` type was renamed throughout Tauri 2.0. + +**Solution:** +```rust +// ❌ v1 +let window: tauri::Window = app.get_window("main").unwrap(); +let builder = tauri::WindowBuilder::new(&app, "main", tauri::WindowUrl::App("index.html".into())); + +// ✅ v2 +let window: tauri::WebviewWindow = app.get_webview_window("main").unwrap(); +let builder = tauri::WebviewWindowBuilder::new(&app, "main", tauri::WebviewUrl::App("index.html".into())); +``` + +--- + +### B3. `SystemTray` / `Menu` APIs Removed + +**Error:** +``` +error[E0412]: cannot find type `SystemTray` in `tauri` +error[E0412]: cannot find type `Menu` in `tauri` +error[E0412]: cannot find type `CustomMenuItem` in `tauri` +error[E0412]: cannot find type `Submenu` in `tauri` +``` + +**Cause:** All menu and tray types were refactored into sub-modules using the `muda` crate. + +**Solution:** +```rust +// ❌ v1 +let menu = tauri::Menu::with_items(app, items)?; +let item = tauri::CustomMenuItem::new("id", "Label"); +let tray = tauri::SystemTray::new(); + +// ✅ v2 +use tauri::menu::{MenuBuilder, MenuItemBuilder, PredefinedMenuItem, SubmenuBuilder}; +use tauri::tray::TrayIconBuilder; + +let menu = MenuBuilder::new(app) + .item(MenuItemBuilder::with_id("toggle", "Toggle").build(app)?) + .build(app)?; + +let tray = TrayIconBuilder::with_id("my-tray") + .menu(&menu) + .on_menu_event(|app, event| { /* handle */ }) + .on_tray_icon_event(|tray, event| { /* handle */ }) + .build(app)?; +``` + +--- + +### B4. `App::clipboard_manager` / `get_cli_matches` / `global_shortcut_manager` Removed + +**Error:** +``` +error[E0599]: no method named 'clipboard_manager' found +error[E0599]: no method named 'get_cli_matches' found +error[E0599]: no method named 'global_shortcut_manager' found +error[E0599]: no method named 'fs_scope' found +``` + +**Cause:** These methods were moved to their respective plugins. + +**Solution:** +```rust +// ❌ v1 +app.clipboard_manager().write_text("text"); +app.get_cli_matches(); +app.global_shortcut_manager().register("Ctrl+K", || {}); +Manager::fs_scope(&app); + +// ✅ v2 +// Add plugin to Cargo.toml: tauri-plugin-clipboard-manager = "2" +use tauri_plugin_clipboard_manager::ClipboardExt; +app.clipboard().write_text("text".into()).unwrap(); + +// Add plugin: tauri-plugin-cli = "2" +use tauri_plugin_cli::CliExt; +let matches = app.cli().matches(); + +// Add plugin: tauri-plugin-global-shortcut = "2" +use tauri_plugin_global_shortcut::GlobalShortcutExt; +app.global_shortcut().on_shortcuts("Ctrl+K", |_| {}); + +// FS scope +use tauri_plugin_fs::FsExt; +// scope is now accessed via FsExt trait +``` + +--- + +### B5. `tauri::updater` Module Removed + +**Error:** +``` +error[E0432]: unresolved import `tauri::updater` +``` + +**Cause:** The updater was extracted into a plugin. The built-in auto-update dialog was also removed. + +**Solution:** Add `tauri-plugin-updater = "2"` to `Cargo.toml`. The updater no longer has an automatic dialog — you must implement update checking and installation manually: +```rust +use tauri_plugin_updater::UpdaterExt; + +// Check for updates +let update = app.updater().check().await?; +if update.is_update_available() { + update.download_and_install(|chunk, content_len, received| { + // Progress callback + }, || { + // Install callback + }).await?; +} +``` + +--- + +### B6. Cargo Feature Names Changed + +**Error:** +``` +error[E0557]: feature `shell-open-api` is not included +error[E0557]: feature `process-command-api` is not included +error[E0557]: feature `system-tray` is not included +error[E0557]: feature `updater` is not included +``` + +**Cause:** Several Cargo features were renamed or removed in v2. + +**Solution:** +```toml +# ❌ v1 features (REMOVED) +features = ["shell-open-api", "process-command-api", "system-tray", "updater"] + +# ✅ v2 — use plugins instead: +# shell-open-api → tauri-plugin-shell +# process-command-api → tauri-plugin-shell +# system-tray → renamed to "tray-icon" feature +# updater → tauri-plugin-updater +``` + +--- + +### B7. JavaScript Import Path Changes + +**Error:** +``` +Module not found: @tauri-apps/api/tauri +``` + +**Cause:** The `@tauri-apps/api/tauri` module was renamed to `@tauri-apps/api/core` in v2. + +**Solution:** +```javascript +// ❌ v1 +import { invoke } from '@tauri-apps/api/tauri'; +import { Window } from '@tauri-apps/api/window'; +import { open } from '@tauri-apps/api/dialog'; +import { readFile } from '@tauri-apps/api/fs'; + +// ✅ v2 +import { invoke } from '@tauri-apps/api/core'; +import { WebviewWindow } from '@tauri-apps/api/webviewWindow'; +import { open } from '@tauri-apps/plugin-dialog'; +import { readFile } from '@tauri-apps/plugin-fs'; +``` + +--- + +## Category C: Async Command & Thread Safety Errors + +### C1. Borrowed Arguments in Async Commands + +**Error:** +``` +error[E0757]: `value` has lifetime `'a` that is not constrained by the fn body +``` +Or generic lifetime errors. + +**Cause:** Async commands are executed via `async_runtime::spawn`, which requires `'static` lifetimes. Borrowed types like `&str`, `&Path` cannot be used directly. + +**Solution — Option A:** Convert to owned types: +```rust +// ❌ WRONG +#[tauri::command] +async fn process(data: &str) -> String { + some_async_fn().await; + data.to_string() +} + +// ✅ CORRECT — use owned String +#[tauri::command] +async fn process(data: String) -> String { + some_async_fn().await; + data +} +``` + +**Solution — Option B:** Wrap return in `Result`: +```rust +#[tauri::command] +async fn process(data: &str) -> Result { + some_async_fn().await; + Ok(data.to_string()) +} +``` + +--- + +### C2. `std::sync::Mutex` Not `Send` Across `.await` + +**Error:** +``` +error[E0277]: `MutexGuard>` cannot be sent between threads safely +``` + +**Cause:** Tauri's async runtime is multi-threaded. `std::sync::MutexGuard` is NOT `Send`, so holding a lock across an `.await` point causes a compile error. + +**Solution:** Use `tokio::sync::Mutex` instead: +```rust +// ❌ WRONG — std::sync::MutexGuard is not Send +use std::sync::Mutex; + +#[tauri::command] +async fn process(state: State<'_, Mutex>) { + let guard = state.lock().unwrap(); + some_async_fn().await; // ERROR here! +} + +// ✅ CORRECT — tokio::sync::MutexGuard IS Send +use tokio::sync::Mutex; + +#[tauri::command] +async fn process(state: State<'_, Mutex>) { + let guard = state.lock().await; + some_async_fn().await; // OK! +} +``` + +--- + +### C3. `std::sync::RwLock` Not `Send` Across `.await` + +**Error:** +``` +error[E0277]: `RwLockReadGuard` cannot be sent between threads safely +``` + +**Cause:** Same as C2 but with `RwLock`. `std::sync::RwLockReadGuard` / `RwLockWriteGuard` is NOT `Send`. + +**Solution:** Use `tokio::sync::RwLock` for async contexts: +```rust +// ❌ WRONG +use std::sync::RwLock; +let guard = state.read().unwrap(); +some_async_fn().await; + +// ✅ CORRECT +use tokio::sync::RwLock; +let guard = state.read().await; +some_async_fn().await; +``` + +--- + +### C4. Non-`Send` Types (`Rc`, `RefCell`) in Async Commands + +**Error:** +``` +error[E0277]: `Rc` cannot be sent between threads safely +error[E0277]: `RefCell` cannot be sent between threads safely +``` + +**Cause:** `Rc`, `RefCell`, and `Cell` are not `Send`. They cannot exist across `.await` points in Tauri's multi-threaded async runtime. + +**Solution:** Replace with thread-safe alternatives: +```rust +// ❌ WRONG +use std::rc::Rc; +use std::cell::RefCell; + +// ✅ CORRECT +use std::sync::Arc; // Instead of Rc +use tokio::sync::Mutex; // Instead of RefCell +use std::sync::atomic::{AtomicUsize, Ordering}; // Instead of Cell for primitives +``` + +--- + +## Category D: Configuration (`tauri.conf.json`) Errors + +### D1. V1 Config Keys in V2 Project + +**Error:** +``` +Error: tauri.conf.json error on `build`: Additional properties are not allowed ('devPath', 'distDir' were unexpected) +``` + +**Cause:** Using v1 config key names (`devPath`, `distDir`) in a v2 project. + +**Solution:** +```json +// ❌ v1 +{ + "build": { + "devPath": "http://localhost:1420", + "distDir": "../dist" + } +} + +// ✅ v2 +{ + "build": { + "devUrl": "http://localhost:1420", + "frontendDist": "../dist" + } +} +``` + +--- + +### D2. V1 `allowlist` Key Not Recognized + +**Error:** +``` +Error: tauri.conf.json error: Additional properties are not allowed ('allowlist' was unexpected) +``` + +**Cause:** The v1 `allowlist` was completely replaced by the capabilities/permissions ACL system in v2. + +**Solution:** Remove `allowlist` entirely from `tauri.conf.json`. Create capability files in `src-tauri/capabilities/`: +```json +{ + "$schema": "../gen/schemas/desktop-schema.json", + "identifier": "default", + "windows": ["main"], + "permissions": ["core:default", "fs:default", "dialog:default"] +} +``` + +--- + +### D3. V1 `tauri` Section Instead of `app` + +**Error:** +``` +Error: tauri.conf.json error: Additional properties are not allowed ('tauri' was unexpected) +``` + +**Cause:** The top-level `tauri` section was renamed to `app` in v2. + +**Solution:** +```json +// ❌ v1 +{ + "tauri": { + "windows": [...], + "security": {...} + } +} + +// ✅ v2 +{ + "app": { + "windows": [...], + "security": {...} + } +} +``` + +--- + +### D4. `beforeDevCommand` Terminated with Non-Zero Status + +**Error:** +``` +Error: The "beforeDevCommand" terminated with a non-zero status code. ELIFECYCLE Command failed with exit code 1. +``` + +**Cause:** The npm script referenced in `beforeDevCommand` fails. Common causes: wrong port, missing dependency, or port conflict. + +**Solution:** +1. Verify `beforeDevCommand` matches an actual script in `package.json` +2. Ensure ports match between `devUrl` and your actual dev server +3. Check that all npm dependencies are installed: `npm install` + +--- + +### D5. `frontendDist` Points to Wrong Directory + +**Error:** +``` +AssetNotFound("index.html") +``` +Or a blank white screen in production builds. + +**Cause:** `build.frontendDist` points to a directory that doesn't contain the built frontend output. + +**Solution:** Verify your bundler's output directory matches `frontendDist`: +| Framework | Default Output | `frontendDist` | +|-----------|---------------|-----------------| +| Vite | `dist/` | `../dist` | +| Next.js (export) | `out/` | `../out` | +| SvelteKit (static) | `build/` | `../build` | +| CRA | `build/` | `../build` | + +--- + +### D6. `tauri.conf.json` Not Found on Mobile Dev + +**Error:** +``` +Couldn't recognize the current folder as a Tauri project. It must contain a 'tauri.conf.json' +``` + +**Cause:** The project uses `tauri.config.json` (also valid) but the mobile subcommand doesn't handle both names correctly. + +**Solution:** Rename to `tauri.conf.json`: +```bash +mv src-tauri/tauri.config.json src-tauri/tauri.conf.json +``` + +--- + +## Category E: Capabilities & Permission Errors + +### E1. Plugin Command Not Allowed — "Plugin Not Found" + +**Error:** +``` +dialog.open not allowed. Plugin not found +fs.create not allowed. Plugin not found +http.request not allowed. Plugin not found +``` + +**Cause:** **The #1 most common Tauri v2 error.** The plugin may be installed in Rust and JS, but no capability file grants permission for its commands. + +**Solution:** Add permissions to `src-tauri/capabilities/default.json`: +```json +{ + "identifier": "default", + "windows": ["main"], + "permissions": [ + "dialog:default", + "fs:default", + "http:default" + ] +} +``` +Or use the CLI to auto-generate: `npx tauri add dialog` (this creates the capability file for you). + +--- + +### E2. `event.listen not allowed. Command not found` + +**Error:** +``` +event.listen not allowed. Command not found +``` + +**Cause:** Even core event functions require permission in v2. + +**Solution:** Add event permissions: +```json +{ + "permissions": [ + "core:event:default" + ] +} +``` +Or be specific: `"core:event:allow-listen"`, `"core:event:allow-emit"`. + +--- + +### E3. `Path not allowed on the configured scope` + +**Error:** +``` +Path not allowed on the configured scope +PermissionDenied +forbidden path +``` + +**Cause:** The FS plugin enforces scope-based path restrictions. By default, only specific directories are accessible. + +**Solution:** Add scope permissions: +```json +{ + "identifier": "fs-scope-capability", + "windows": ["main"], + "permissions": [ + { + "identifier": "fs:allow-read", + "allow": [{ "path": "$HOME/**" }, { "path": "$APPDATA/**" }] + }, + { + "identifier": "fs:allow-write", + "allow": [{ "path": "$APPDATA/**" }] + } + ] +} +``` +Available scope variables: `$APPDATA`, `$HOME`, `$APPCONFIG`, `$APPCACHE`, `$APPLOG`, `$RESOURCE`, `$EXE`. + +--- + +### E4. `webview.close not allowed` Despite Permission Being Set + +**Error:** +``` +webview.close not allowed +``` +Persists even after adding `webview:allow-close` to capabilities. + +**Cause:** The capability file is malformed, or the permission identifier string doesn't exactly match what the plugin expects. + +**Solution:** Verify the exact permission identifier from the plugin's documentation or generated schema. Ensure the `windows` array contains the correct window label. + +--- + +### E5. Permissions Work in Dev But Fail in Build + +**Error:** Permission/ACL errors only appear after `npm run tauri build`, not during `npm run tauri dev`. + +**Cause:** Dev mode may run in a less restrictive context. Production builds enforce strict ACL validation. + +**Solution:** Always test capabilities in a production build. Verify all capability files are in `src-tauri/capabilities/` and properly referenced. + +--- + +### E6. PluginInitialization Error with Old Config + +**Error:** +``` +error while running tauri application: PluginInitialization("http", "invalid type: map, expected unit") +``` + +**Cause:** Using v1-style `plugins` configuration with `scope` maps in `tauri.conf.json`. + +**Solution:** Remove old config from `tauri.conf.json`: +```json +// ❌ REMOVE THIS from tauri.conf.json +{ + "plugins": { + "http": { + "scope": ["http://my.api.host/*"] + } + } +} +``` +Use the v2 capabilities system instead (see E3). + +--- + +### E7. `program not allowed on the configured shell scope` + +**Error:** +``` +program not allowed on the configured shell scope +``` + +**Cause:** The shell plugin restricts which programs can be executed via scope configuration. + +**Solution:** Add the program to the shell scope: +```json +{ + "identifier": "shell-capability", + "windows": ["main"], + "permissions": [ + { + "identifier": "shell:allow-execute", + "allow": [ + { "name": "git", "args": true }, + { "name": "node", "args": true }, + { "name": "python3", "args": true } + ] + }, + { + "identifier": "shell:allow-spawn", + "allow": [ + { "name": "my-sidecar", "sidecar": true } + ] + } + ] +} +``` + +--- + +## Category F: Plugin Integration Errors + +### F1. Plugin Not Registered in Builder + +**Error:** Generic "command not found" or "plugin not found" when using any plugin API. + +**Cause:** The plugin crate is added to `Cargo.toml` but not registered in the `tauri::Builder`. + +**Solution:** Every plugin requires `.plugin()` registration: +```rust +// ❌ WRONG — plugin installed but not registered +tauri::Builder::default() + .run(tauri::generate_context!()) + +// ✅ CORRECT — all plugins registered +tauri::Builder::default() + .plugin(tauri_plugin_opener::init()) + .plugin(tauri_plugin_dialog::init()) + .plugin(tauri_plugin_fs::init()) + .plugin(tauri_plugin_http::init()) + .run(tauri::generate_context!()) +``` + +--- + +### F2. `tauri-plugin-process` — `request_restart` Not Found + +**Error:** +``` +error[E0599]: no method named 'request_restart' found for struct 'AppHandle' +``` + +**Cause:** In Tauri 2.0, `exit()` and `restart()` are core API methods, not plugin methods. + +**Solution:** Use the core API directly: +```rust +// ❌ WRONG +app.handle().process().restart(); + +// ✅ CORRECT — core API +app_handle.restart(); +app_handle.exit(0); +``` + +--- + +### F3. SQL Plugin Top-Level-Await Error (Webpack) + +**Error:** +``` +ERROR in ./src/App.js: Module parse failed: The top-level-await experiment is not enabled +``` + +**Cause:** The SQL plugin's JS import uses top-level await, which requires bundler configuration changes. + +**Solution:** Enable in webpack config: +```javascript +// webpack.config.js +module.exports = { + experiments: { + topLevelAwait: true + } +}; +``` +Or use dynamic imports instead of static imports. + +--- + +### F4. `tauri-cli v2.9.0` Compilation Failure + +**Error:** +``` +error[E0412]: cannot find type 'Error' in crate 'tauri_macos_sign' +``` + +**Cause:** Version-specific bug in tauri-cli. + +**Solution:** Use a different CLI version or update to the latest: +```bash +npm install @tauri-apps/cli@latest +``` + +--- + +### F5. App Unresponsive After Plugin Dialog Calls + +**Error:** App freezes/becomes unresponsive with no error message. + +**Cause:** Dialog plugin calls can block the main thread on some platforms by competing for the same Windows message loop. + +**Solution:** Ensure plugin calls are async. Avoid calling multiple dialog operations simultaneously. Update to the latest plugin version. + +--- + +## Category G: IPC / Command Runtime Errors + +### G1. Command Not Found at Runtime + +**Error:** +``` +Error: command not found +``` +(from frontend JS `invoke()` call) + +**Cause:** The Rust command function exists but is **not registered** in `generate_handler![]`. + +**Solution:** +```rust +// ❌ WRONG — command exists but not registered +#[tauri::command] +fn my_command() -> String { "hello".into() } + +tauri::Builder::default() + .invoke_handler(tauri::generate_handler![some_other_command]) // missing! + +// ✅ CORRECT +tauri::Builder::default() + .invoke_handler(tauri::generate_handler![my_command, some_other_command]) +``` + +--- + +### G2. Only Last `invoke_handler` Takes Effect + +**Error:** Some commands silently don't work — only commands in the last `invoke_handler` call work. + +**Cause:** Calling `.invoke_handler()` multiple times — each call **overwrites** the previous one. + +**Solution:** Pass ALL commands in a single call: +```rust +// ❌ WRONG — second call overwrites first +.invoke_handler(tauri::generate_handler![cmd_a]) +.invoke_handler(tauri::generate_handler![cmd_b]) + +// ✅ CORRECT +.invoke_handler(tauri::generate_handler![cmd_a, cmd_b]) +``` + +--- + +### G3. `pub` on Commands in `lib.rs` Causes Multiple Definition Error + +**Error:** +``` +error[E0255]: the name '__cmd__my_command' is defined multiple times +``` + +**Cause:** Commands in `lib.rs` cannot be `pub` due to glue code generation. + +**Solution:** Remove `pub` from commands in `lib.rs`, or move them to a separate module where they MUST be `pub`: +```rust +// In lib.rs — do NOT use pub +#[tauri::command] +fn my_command() -> String { /* ... */ } + +// In commands.rs — MUST use pub +#[tauri::command] +pub fn my_command() -> String { /* ... */ } +``` + +--- + +### G4. Error Types Don't Implement `Serialize` + +**Error:** +``` +error[E0277]: `std::io::Error` doesn't implement `serde::Serialize` +``` + +**Cause:** Standard library error types don't implement `Serialize`, which Tauri requires for crossing the IPC boundary. + +**Solution:** Create a custom error type: +```rust +#[derive(Debug, thiserror::Error)] +enum AppError { + #[error("IO error: {0}")] + Io(#[from] std::io::Error), + #[error("Network error: {0}")] + Network(#[from] reqwest::Error), +} + +impl serde::Serialize for AppError { + fn serialize(&self, serializer: S) -> Result + where S: serde::ser::Serializer { + serializer.serialize_str(self.to_string().as_ref()) + } +} +``` + +--- + +### G5. `window.__TAURI__` Not Defined + +**Error:** +``` +ReferenceError: __TAURI__ is not defined +``` + +**Cause:** (1) Running frontend code outside the Tauri webview (browser/SSR). (2) `withGlobalTauri` not set to `true`. (3) Code runs before Tauri injects IPC. + +**Solution:** +1. For bundled apps: use `import { invoke } from '@tauri-apps/api/core'` +2. For vanilla JS: set `"app": { "withGlobalTauri": true }` in `tauri.conf.json` +3. Never run Tauri API code in SSR (Next.js server components) +4. Wrap calls in DOMContentLoaded or wait for `tauri://ready` event + +--- + +### G6. Tauri 2.0.2 UTF-8 Payload Breaking Change + +**Error:** Invoke calls break with encoding errors after upgrading to Tauri 2.0.2. + +**Cause:** Tauri 2.0.2 introduced strict UTF-8 validation on invoke payloads. Non-UTF-8 data now causes errors. + +**Solution:** Base64-encode all binary data before passing through invoke. Pin Tauri versions in `Cargo.toml` to prevent surprise upgrades. + +--- + +## Category H: Webview & Window Runtime Errors + +### H1. `failed to create webview: WebView2 error` + +**Error:** +``` +error while running tauri application: Runtime(CreateWebview(WebView2Error(WindowsError(Error { code: 0x80070057, message: "The parameter is incorrect." })))) +``` +Or `0x800700AA` ("The requested resource is in use"). + +**Cause:** Multiple possible causes: (1) WebView2 runtime not installed/corrupted, (2) Invalid `additional_browser_args`, (3) Another process holding a WebView2 lock, (4) Data folder creation failure. + +**Solution:** +1. Install/repair WebView2 runtime +2. Remove custom `additional_browser_args` from config +3. Kill old Tauri dev instances: `taskkill /f /im .exe` +4. For multi-webview support, ensure `features = ["unstable"]` in Cargo.toml + +--- + +### H2. Blank/Frozen Screen on Additional WebviewWindow + +**Error:** New window appears as a frozen white screen that cannot be closed. + +**Cause:** The webview doesn't have a valid URL, capabilities aren't configured for the new window's label, or the webview was created before the parent window was fully ready. + +**Solution:** +```javascript +const { WebviewWindow } = window.__TAURI__.webviewWindow; +const webview = new WebviewWindow('unique-label', { + url: 'path-to-page.html', + title: 'Secondary Window' +}); +webview.once('tauri://error', (e) => console.error('Window error:', e)); +``` +Ensure capabilities include the new window's label. + +--- + +### H3. Cannot Create Child Webview Without Unstable Feature + +**Error:** Webview creation from JavaScript silently fails. + +**Cause:** Multi-webview support requires the `unstable` feature flag. + +**Solution:** Add to `Cargo.toml`: +```toml +tauri = { version = "2", features = ["unstable"] } +``` +Note: This uses nightly/unstable Rust features. + +--- + +### H4. GDK Main Thread Error (Linux) + +**Error:** +``` +* GDK may only be used from the main thread +``` + +**Cause:** Some Tauri window API calls on Linux internally use GDK, which must be called from the main thread. + +**Solution:** Ensure all window operations are dispatched to the main thread. Update to the latest Tauri version — many thread safety fixes have been merged. + +--- + +## Category I: Event System Errors + +### I1. Events Emitted But Not Received by New Window + +**Error:** Events emitted to a newly created window are not received the first time. + +**Cause:** Race condition — the event is emitted before the listener is attached in the new window. + +**Solution:** Use a handshake pattern: +```javascript +// In new window — announce ready +import { emit } from '@tauri-apps/api/event'; +emit('window-ready', { label: 'my-window' }); + +// In main window — respond after ready signal +listen('window-ready', (event) => { + emitTo(event.payload.label, 'initial-data', myData); +}); +``` + +--- + +### I2. Events Not Working Between Windows + +**Error:** Events emitted from one window are not received by another window. + +**Cause:** Using `emit()` (which broadcasts to all) vs. `emitTo()` (which targets a specific window) incorrectly, or listeners scoped incorrectly. + +**Solution:** +```rust +// Emit to ALL windows +app.emit("my-event", payload)?; + +// Emit to a SPECIFIC window +app.emit_to("settings-panel", "my-event", payload)?; +``` +```javascript +// Frontend: listen globally +import { listen } from '@tauri-apps/api/event'; +const unlisten = await listen('my-event', handler); + +// Frontend: listen on specific window only +import { getCurrentWebviewWindow } from '@tauri-apps/api/webviewWindow'; +const appWebview = getCurrentWebviewWindow(); +const unlisten2 = await appWebview.listen('my-event', handler); +``` + +--- + +### I3. Rapid Event Emission Causes Panic + +**Error:** App crashes when emitting large numbers of events rapidly. + +**Cause:** Internal buffer overflow or deadlock in the event system. + +**Solution:** Throttle/debounce event emission. For high-frequency data, use `Channel` instead of events: +```rust +use tauri::ipc::Channel; + +#[tauri::command] +fn stream_data(on_event: Channel) { + for item in data_source { + on_event.send(item).unwrap(); + } +} +``` + +--- + +## Category J: Content Security Policy (CSP) Errors + +### J1. `Refused to connect to 'http://ipc.localhost'` + +**Error:** +``` +Refused to connect to 'http://ipc.localhost/test' because it violates the document's Content Security Policy. +``` + +**Cause:** External URLs loaded in webviews have their own CSP that doesn't allow connections to Tauri's IPC endpoint. + +**Solution:** Configure CSP to include IPC: +```json +{ + "app": { + "security": { + "csp": "default-src 'self'; connect-src 'self' ipc: http://ipc.localhost https://your-url.com" + } + } +} +``` +For maximum compatibility with injected scripts on external pages: `"csp": null` (use with caution). + +--- + +### J2. CSS-in-JS Libraries Blocked by CSP + +**Error:** Styles/scripts from styled-components, emotion, or other CSS-in-JS libraries are blocked. + +**Cause:** Default CSP doesn't allow inline styles. + +**Solution:** Add `'unsafe-inline'` to `style-src`: +```json +{ + "app": { + "security": { + "csp": "default-src 'self'; style-src 'self' 'unsafe-inline'; script-src 'self'" + } + } +} +``` + +--- + +## Category K: Frontend Integration Errors (Vite / Next.js / SvelteKit) + +### K1. Vite Dev Server Not Connecting / White Screen + +**Error:** Tauri window opens but shows blank white screen. Dev server connection not established. + +**Cause:** Port mismatch between `devUrl` in `tauri.conf.json` and Vite's actual port. + +**Solution:** +1. Ensure `devUrl` matches Vite's actual port: `"devUrl": "http://localhost:5173"` +2. For mobile, use `process.env.TAURI_DEV_HOST` as the host in Vite config +3. Set `server.host` in `vite.config.js` to allow network access + +--- + +### K2. Vite Watches `src-tauri` — Infinite Recompilation + +**Error:** App keeps recompiling Rust code repeatedly in an infinite loop. + +**Cause:** Vite's file watcher detects changes in `src-tauri/` (from Cargo build output) and triggers re-runs. + +**Solution:** Add `src-tauri` to Vite's ignore list: +```javascript +// vite.config.js +export default defineConfig({ + server: { + watch: { + ignored: ["**/src-tauri/**"] + } + } +}); +``` + +--- + +### K3. Next.js App Router Breaks in Production + +**Error:** `useEffect` hooks broken, syntax errors in chunk files, component rendering failures in production. + +**Cause:** Next.js App Router uses React Server Components and advanced chunking that conflicts with Tauri's custom protocol. + +**Solution:** Use static export only: +```javascript +// next.config.js +module.exports = { + output: 'export', // Required — no SSR + images: { unoptimized: true }, // No server-side image optimization +}; +``` +Add `'use client'` directives to all interactive components. + +--- + +### K4. Next.js `assetPrefix` Breaks Hot Reload + +**Error:** Hot reload doesn't work when `assetPrefix` is set for Tauri. + +**Cause:** `assetPrefix` changes the URL for WebSocket connections, breaking HMR. + +**Solution:** Only set `assetPrefix` in production: +```javascript +// next.config.js +module.exports = { + output: 'export', + assetPrefix: process.env.NODE_ENV === 'production' ? './' : undefined, +}; +``` + +--- + +### K5. Next.js Standalone Output — `asset not found: index.html` + +**Error:** +``` +asset not found: index.html +``` + +**Cause:** Next.js standalone output doesn't produce a static `index.html` file. + +**Solution:** Use `output: "export"`, NOT `standalone`: +```javascript +module.exports = { + output: 'export', // Required for Tauri + // NOT output: 'standalone' +}; +``` + +--- + +### K6. SvelteKit Blank Screen / PostCSS Errors + +**Error:** Blank white screen or `[postcss] Internal server error`. + +**Cause:** SvelteKit's routing conflicts with Tauri's static file serving. + +**Solution:** Use `@sveltejs/adapter-static`: +```javascript +// svelte.config.js +import adapter from '@sveltejs/adapter-static'; + +export default { + kit: { + adapter: adapter({ fallback: 'index.html' }) + } +}; +``` +Add to root layout: `export const ssr = false;` + +--- + +## Category L: WebSocket Errors + +### L1. WebSocket Connection Closing / "Broken Pipe" + +**Error:** WebSocket connection closes unexpectedly after app has been open for a long time. + +**Cause:** Idle timeouts or OS-level connection cleanup. + +**Solution:** Implement ping/pong keepalive in custom WebSocket connections: +```javascript +const ws = new WebSocket('ws://127.0.0.1:8080'); + +// Keepalive +setInterval(() => { + if (ws.readyState === WebSocket.OPEN) { + ws.send(JSON.stringify({ type: 'ping' })); + } +}, 30000); +``` + +--- + +### L2. WebSocket Plugin — Unstable Connections + +**Error:** Messages not received right after connection with `tauri-plugin-websocket`. + +**Cause:** The WebSocket connection may not be fully initialized before messages are sent. + +**Solution:** Wait for the `onopen` event: +```javascript +import WebSocket from '@tauri-apps/plugin-websocket'; + +const ws = await WebSocket.connect('ws://localhost:8080'); +// Ensure ready before sending +ws.addListener((msg) => { + console.log('Received:', msg); +}); +``` + +--- + +### L3. WebSocket + Tauri Client Conflict + +**Error:** WebSocket client code and Tauri app cannot run simultaneously. + +**Cause:** Resource conflicts between the Tauri WebView and WebSocket connections, especially on mobile. + +**Solution:** Use `tauri-plugin-websocket` instead of raw `WebSocket` API for mobile compatibility. + +--- + +## Category M: Path & Asset Protocol Errors + +### M1. 403 Forbidden on Asset Protocol URLs + +**Error:** `403 Forbidden` when accessing files via `asset://` protocol. + +**Cause:** The asset protocol has a scope restricting which directories can be accessed. + +**Solution:** Configure asset protocol scope: +```json +{ + "identifier": "asset-capability", + "permissions": [ + { + "identifier": "fs:allow-read", + "allow": [{ "path": "$RESOURCE/**" }] + } + ] +} +``` +Use `convertFileSrc()` from `@tauri-apps/api/core` for proper path conversion. + +--- + +### M2. `resource_dir()` Returns Unknown Path + +**Error:** `PathResolver.resource_dir()` returns empty or unknown path. + +**Cause:** A custom `target-dir` in `~/.cargo/config.toml` breaks resource resolution logic. + +**Solution:** Remove global `target-dir` setting, or configure it per-project instead of globally. + +--- + +### M3. Path Traversal Prevention Blocking Valid Paths + +**Error:** `path traversal` error from `@tauri-apps/plugin-fs`. + +**Cause:** The FS plugin blocks paths containing `..`. + +**Solution:** Normalize paths before use: +```javascript +import { resolve } from '@tauri-apps/api/path'; +const normalizedPath = await resolve('some', 'relative', 'path'); +``` + +--- + +## Category N: Shell & Sidecar Errors + +### N1. Sidecar Binary Not Found + +**Error:** +``` +Failed to spawn my-binary: Io(Os { code: 3, kind: NotFound }) +``` + +**Cause:** The sidecar binary doesn't follow Tauri's naming convention. Tauri appends the target triple to the binary name. + +**Solution:** +```json +// tauri.conf.json +{ + "bundle": { + "externalBin": ["binaries/my-binary"] + } +} +``` +Name the binary with the target triple suffix: +- Windows: `my-binary-x86_64-pc-windows-msvc.exe` +- macOS: `my-binary-aarch64-apple-darwin` +- Linux: `my-binary-x86_64-unknown-linux-gnu` + +Reference in Rust without the suffix: +```rust +app.shell().sidecar("binaries/my-binary").unwrap() +``` + +--- + +## Category O: Mobile Build Errors (iOS & Android) + +### O1. `xcodebuild exited with code 65` + +**Error:** +``` +error: failed to run custom build command for tauri v2 ... xcodebuild exited with code 65 +``` + +**Cause:** iOS build failure. Common causes: code signing issues, stale build artifacts, Xcode version incompatibility. + +**Solution:** +1. Open Xcode project: `open src-tauri/gen/apple/Project.xcworkspace` +2. Set Signing & Capabilities → Team +3. Clean build: `Cmd+Shift+K` in Xcode +4. Clean pods: `cd src-tauri/gen/apple && rm -rf build Pods && pod install` + +--- + +### O2. `can't find crate for core` (Missing Mobile Target) + +**Error:** +``` +error[E0463]: can't find crate for `core` +``` +When building for iOS or Android. + +**Cause:** The Rust target for the mobile platform is not installed. + +**Solution:** +```bash +# iOS +rustup target add aarch64-apple-ios + +# Android (all targets) +rustup target add aarch64-linux-android armv7-linux-androideabi i686-linux-android x86_64-linux-android +cargo install cargo-ndk +``` + +--- + +### O3. `building for 'iOS', but linking in object file built for 'macOS'` + +**Error:** +``` +building for 'iOS', but linking in object file built for 'macOS' +``` + +**Cause:** A native dependency was compiled for the host platform instead of the iOS target. + +**Solution:** Check which dependency causes the issue: `cargo build --target aarch64-apple-ios -v`. Ensure all dependencies support cross-compilation to iOS. + +--- + +### O4. Android Build Fails — `Cannot find module 'tauri'` + +**Error:** +``` +Cannot find module 'tauri' during Gradle build +``` + +**Cause:** Node.js executable can't be found when Gradle's BuildTask runs. + +**Solution:** Ensure Node.js is available system-wide. Use `npx tauri` or configure the Gradle BuildTask to use the correct node path. + +--- + +### O5. Android App Crashes on Launch + +**Error:** App immediately crashes after deployment to Android device/emulator. + +**Cause:** Missing Android SDK components, incorrect NDK configuration, or incompatible Gradle/AGP versions. + +**Solution:** +1. Ensure correct Android SDK and NDK are installed +2. Run `npx tauri android init` to set up properly +3. Check `android/app/build.gradle` has correct Tauri integration +4. Verify ADB connection: `adb devices` + +--- + +### O6. `tauri android dev` Hangs Indefinitely + +**Error:** Command hangs with no output or progress. + +**Cause:** Emulator/device connection failure or Gradle build hanging. + +**Solution:** +1. Verify ADB: `adb devices` +2. Clean Gradle cache: `cd android && ./gradlew clean` +3. Use a physical device instead of emulator +4. Increase Gradle memory in `android/gradle.properties` + +--- + +### O7. `mobile_entry_point` Conflicts with `#[tokio::main]` + +**Error:** App crashes on iOS when using `#[tokio::main]` with `mobile_entry_point`. + +**Cause:** `mobile_entry_point` and `#[tokio::main]` generate conflicting function signatures. + +**Solution:** +```rust +// ❌ WRONG +#[cfg_attr(mobile, tauri::mobile_entry_point)] +#[tokio::main] +pub async fn run() { /* ... */ } + +// ✅ CORRECT — use async_runtime::block_on +#[cfg_attr(mobile, tauri::mobile_entry_point)] +pub fn run() { + tauri::async_runtime::block_on(async { + tauri::Builder::default() + .run(tauri::generate_context!()) + .expect("error while running tauri application"); + }); +} +``` + +--- + +### O8. No Code Signing Certificates Found (iOS) + +**Error:** +``` +No code signing certificates found. You must add one and set the certificate development team ID. +``` + +**Cause:** No Apple Developer certificate configured. + +**Solution:** Open `src-tauri/gen/apple/Project.xcworkspace` in Xcode → Signing & Capabilities → select Team. Or use environment variables: `APPLE_SIGNING_IDENTITY`, `APPLE_TEAM_ID`. + +--- + +## Category P: Platform-Specific Build Errors + +### P1. Linux — Missing System Dependencies + +**Error:** Build fails with GTK/WebKit-related errors. + +**Cause:** Missing system libraries for GTK/WebKit development. + +**Solution:** +```bash +# Ubuntu/Debian +sudo apt install libwebkit2gtk-4.1-dev libgtk-3-dev libayatana-appindicator3-dev \ + librsvg2-dev libsoup-3.0-dev + +# Fedora +sudo dnf install webkit2gtk4.1-devel gtk3-devel libappindicator-gtk3-devel \ + librsvg2-devel libsoup3-devel + +# Arch +sudo pacman -S webkit2gtk-4.1 gtk3 libappindicator-gtk3 librsvg libsoup3 +``` + +--- + +### P2. Linux — Failed to Find ICNS Encoder + +**Error:** +``` +error: failed to compile tauri-bundler: failed to find ICNS encoder +``` + +**Cause:** Missing icon tools for macOS bundle creation on Linux. + +**Solution:** `sudo apt install icnsutils` (Debian/Ubuntu) or equivalent package. + +--- + +### P3. Linux — Failed to Run `linuxdeploy` + +**Error:** +``` +error: failed to bundle project: failed to run linuxdeploy +``` + +**Cause:** Missing AppImage bundling dependencies. + +**Solution:** Install `linuxdeploy` and `linuxdeploy-plugin-gtk`. Ensure `appimage-builder` is available. + +--- + +## Category Q: Panics & Runtime Crashes + +### Q1. Generic "error while running tauri application" + +**Error:** +``` +thread 'main' panicked at src\main.rs:14:10: +error while running tauri application: +``` + +**Cause:** Top-level error wrapper. The inner error reveals the actual problem — check plugin initialization, WebView creation, or config validation. + +**Solution:** Replace `.expect()` with better error reporting: +```rust +if let Err(e) = tauri::Builder::default() + .plugin(tauri_plugin_http::init()) + .run(tauri::generate_context!()) +{ + eprintln!("Failed to start: {e}"); + std::process::exit(1); +} +``` + +--- + +### Q2. Panic in tauri-runtime-wry on Wayland + +**Error:** +``` +Panic in tauri-runtime-wry during init on Wayland +``` + +**Cause:** Wayland compositors missing `wlr_data_control_manager v1` protocol cause the clipboard crate to panic. + +**Solution:** Use XWayland, or use a Wayland compositor that supports the protocol. + +--- + +### Q3. `EXC_BAD_ACCESS` Crash on iOS + +**Error:** App crashes on physical iPhone with `EXC_BAD_ACCESS` but works in simulator. + +**Cause:** Memory access violations in native code bridging. + +**Solution:** Enable address sanitizer in Xcode. Check for use-after-free or null pointer issues in Rust FFI code. + +--- + +### Q4. Panic When `Builder::setup` Hook Fails + +**Error:** App panics immediately when the `setup` callback returns an error. + +**Cause:** `App::run()` panics when setup fails — no graceful error handling. + +**Solution:** Wrap setup logic properly: +```rust +tauri::Builder::default() + .setup(|app| { + match critical_init(app) { + Ok(_) => Ok(()), + Err(e) => { + eprintln!("Setup failed: {e}"); + Err(e.into()) + } + } + }) + .run(tauri::generate_context!()) +``` + +--- + +## Category R: Error Handling Best Practices + +### R1. Never Panic Inside Tauri Commands + +Panic in a **synchronous** command crashes the app. Panic in an **asynchronous** command causes a Promise that never resolves (silent failure). Always return `Result`: + +```rust +#[derive(Debug, thiserror::Error)] +enum AppError { + #[error(transparent)] + Io(#[from] std::io::Error), + #[error(transparent)] + Network(#[from] reqwest::Error), + #[error("{0}")] + Custom(String), +} + +impl serde::Serialize for AppError { + fn serialize(&self, s: S) -> Result + where S: serde::ser::Serializer { + s.serialize_str(&self.to_string()) + } +} + +#[tauri::command] +fn my_command() -> Result { + let data = std::fs::read_to_string("config.toml")?; + Ok(data) +} +``` + +### R2. Frontend Error Handling + +```javascript +import { invoke } from '@tauri-apps/api/core'; + +try { + const result = await invoke('my_command', { arg: 'value' }); + console.log('Success:', result); +} catch (error) { + console.error('Command failed:', error); + // Show user-friendly error in UI +} +``` + +### R3. Structured Errors for the Frontend + +```rust +#[derive(serde::Serialize)] +#[serde(tag = "kind", content = "message")] +#[serde(rename_all = "camelCase")] +enum ErrorKind { + Io(String), + Network(String), + Custom(String), +} + +impl serde::Serialize for AppError { + fn serialize(&self, s: S) -> Result + where S: serde::ser::Serializer { + let kind = match self { + Self::Io(e) => ErrorKind::Io(e.to_string()), + Self::Network(e) => ErrorKind::Network(e.to_string()), + Self::Custom(msg) => ErrorKind::Custom(msg.clone()), + }; + kind.serialize(s) + } +} +``` +Frontend receives: `{ kind: 'io', message: '...' }` — making it easy to handle errors by type. + +### R4. Cleanup Event Listeners + +```javascript +import { listen } from '@tauri-apps/api/event'; + +// ❌ WRONG — memory leak +useEffect(() => { + listen('my-event', handler); + return () => {}; // No cleanup! +}, []); + +// ✅ CORRECT — proper cleanup +useEffect(() => { + const unlisten = listen('my-event', handler); + return () => { unlisten.then(fn => fn()); }; +}, []); +``` + +--- + +## Quick-Reference: Top 25 Most Common Errors + +| # | Error Message | Category | Quick Fix | +|---|---|---|---| +| 1 | `X not allowed. Plugin not found` | Permission | Add permissions to `capabilities/default.json` | +| 2 | `Additional properties not allowed ('devPath', 'distDir')` | Config | Rename to `devUrl` / `frontendDist` | +| 3 | `__TAURI__ is not defined` | Frontend | Set `withGlobalTauri: true` or use npm imports | +| 4 | `AssetNotFound("index.html")` | Config | Fix `frontendDist` path to match bundler output | +| 5 | `unresolved import 'tauri::api'` | Migration | Replace with plugins (`tauri-plugin-*`) | +| 6 | `cannot find type 'Window' in 'tauri'` | Migration | Use `WebviewWindow` | +| 7 | `failed to create webview: WebView2 error` | Webview | Install WebView2; remove custom browser args | +| 8 | `Path not allowed on the configured scope` | Permission | Add FS scope permissions | +| 9 | `command not found` | IPC | Add command to `generate_handler![]` | +| 10 | `cannot find type 'SystemTray'` | Migration | Use `tauri::tray::TrayIconBuilder` | +| 11 | `lifetime not constrained` in async | Async | Use owned types (`String`, not `&str`) | +| 12 | `MutexGuard cannot be sent between threads` | Async | Use `tokio::sync::Mutex` instead of `std::sync::Mutex` | +| 13 | `xcodebuild exited with code 65` | Mobile | Set signing team in Xcode | +| 14 | `can't find crate for core` | Mobile | `rustup target add ` | +| 15 | `Additional properties not allowed ('allowlist')` | Config | Remove; use v2 capabilities system | +| 16 | `beforeDevCommand terminated with non-zero status` | Config | Fix npm scripts and port numbers | +| 17 | Vite infinite recompilation | Frontend | Add `src-tauri` to `watch.ignored` | +| 18 | Next.js `useEffect` broken in production | Frontend | Use `output: "export"` + `'use client'` | +| 19 | `program not allowed on shell scope` | Shell | Add program to shell capability scope | +| 20 | `Refused to connect to 'http://ipc.localhost'` | CSP | Add `ipc: http://ipc.localhost` to `connect-src` | +| 21 | Only last `invoke_handler` works | IPC | Combine all commands in one `generate_handler![]` | +| 22 | `GDK may only be used from the main thread` | Platform | Update Tauri; avoid cross-thread UI calls | +| 23 | `PluginInitialization("http", "invalid type")` | Config | Migrate old plugins config to v2 capabilities | +| 24 | Sidecar `Io(Os { code: 3 })` | Shell | Fix binary naming with target triple suffix | +| 25 | `error while running tauri application` | Generic | Check inner error; improve error handling |