# Tauri 2.0 Error Resolution Guide — Part 2: Runtime, Platform & Mobile Errors > **Version**: 2.0 | **Last Updated**: 2026-05-31 > **Official Docs**: https://v2.tauri.app > > This file covers Categories I-R and the Quick-Reference (runtime, platform-specific, and mobile errors). Part 1 covers build, config and plugin errors. --- ## Table of Contents 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) **See also**: [Part 1: Build, Config & Plugin Errors](./01-build-config-permission-plugin-errors.md) --- ## 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`. --- ### O9. Android SDK Not Found **Error:** ``` Android SDK not found at ANDROID_HOME. Please set the ANDROID_HOME environment variable. ``` Or Gradle fails with `SDK location not found`. **Cause:** The `ANDROID_HOME` (or `ANDROID_SDK_ROOT`) environment variable is not set, or points to a nonexistent directory. Tauri's Android build requires the Android SDK to be available. **Solution:** 1. Install Android Studio, which bundles the SDK 2. Set the environment variable: ```bash # macOS/Linux — add to ~/.zshrc or ~/.bashrc export ANDROID_HOME="$HOME/Android/Sdk" export PATH="$ANDROID_HOME/platform-tools:$PATH" # Windows — set via System Properties → Environment Variables ANDROID_HOME=C:\Users\\AppData\Local\Android\Sdk ``` 3. Verify: `echo $ANDROID_HOME` and `adb version` 4. Re-run `npx tauri android init` --- ### O10. iOS Development Requires macOS **Error:** ``` iOS is not supported on this platform ``` Or `xcodebuild: command not found` when running on Linux or Windows. **Cause:** iOS builds require Xcode and the Apple toolchain, which are only available on macOS. Cross-compilation to iOS from Linux or Windows is not supported by Tauri. **Solution:** 1. Use a Mac (physical or CI runner like GitHub Actions `macos-latest`) 2. Install Xcode from the Mac App Store 3. Accept the Xcode license: `sudo xcodebuild -license accept` 4. Install CocoaPods: `sudo gem install cocoapods` (or `brew install cocoapods`) 5. For CI, use GitHub Actions with `macos-latest` runner --- ### O11. `pod install` Failed (iOS) **Error:** ``` Pod installation failed. CocoaPods could not find compatible versions for pod "TauriDriver" ``` Or `pod: command not found`. **Cause:** CocoaPods is not installed, outdated, or the Podfile.lock is stale and conflicts with updated dependencies. **Solution:** 1. Ensure CocoaPods is installed: ```bash sudo gem install cocoapods # Or via Homebrew: brew install cocoapods ``` 2. Clean and reinstall pods: ```bash cd src-tauri/gen/apple rm -rf Podfile.lock Pods pod install --repo-update ``` 3. If version conflicts persist, update CocoaPods to the latest version: `sudo gem install cocoapods --pre` 4. Ensure your Xcode Command Line Tools are up to date: `xcode-select --install` --- ## 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 | --- **Back to**: [Part 1: Build, Config & Plugin Errors](./01-build-config-permission-plugin-errors.md)