Rust Tauri Debugging
Debugging techniques for Tauri applications with Rust backend.
When to Use
- •Tauri app crashes or doesn't start
- •IPC commands failing or returning errors
- •State management issues
- •WSL2-specific Tauri problems
- •Build or bundling errors
Quick Diagnosis
App Won't Start
- •
Check console output:
bash# Run with debug output RUST_LOG=debug cargo tauri dev
- •
Check for GTK/WebKit issues (WSL2):
bashexport GDK_BACKEND=x11 export WEBKIT_DISABLE_COMPOSITING_MODE=1 cargo tauri dev
- •
Check for missing dependencies:
bash# Ubuntu/Debian sudo apt install libwebkit2gtk-4.1-dev libgtk-3-dev libayatana-appindicator3-dev librsvg2-dev
IPC Issues
- •
Command not found:
- •Verify function is in
generate_handler!macro - •Check function name matches exactly (no typos)
- •Ensure
#[tauri::command]attribute present
- •Verify function is in
- •
Serialization errors:
- •Check types implement Serialize/Deserialize
- •Verify TypeScript types match Rust types
- •Use Result<T, String> for error handling
- •
Arguments not received:
- •Check parameter names match between Rust and TypeScript
- •Ensure complex types are properly serialized
Debugging Techniques
Enable Logging
rust
// src-tauri/src/main.rs
fn main() {
env_logger::Builder::from_env(
env_logger::Env::default().default_filter_or("debug")
).init();
tauri::Builder::default()
// ...
}
// In commands
#[tauri::command]
fn my_command(input: String) -> Result<String, String> {
log::debug!("my_command called with: {}", input);
// ...
}
DevTools Console
typescript
// Frontend - check for invoke errors
try {
const result = await invoke('command_name', { arg: value });
console.log('Success:', result);
} catch (error) {
console.error('Invoke failed:', error);
}
Inspect IPC Messages
rust
// Add to tauri.conf.json for dev
{
"build": {
"devPath": "http://localhost:5173",
"beforeDevCommand": "bun dev",
"withGlobalTauri": true
}
}
Then in browser console:
javascript
window.__TAURI_IPC__ // Check if available
Common Issues
State Not Persisting
Problem: State resets between command calls
Solution: Use managed state properly:
rust
use std::sync::Mutex;
use tauri::State;
struct AppState {
data: Mutex<Vec<String>>,
}
#[tauri::command]
fn add_item(item: String, state: State<'_, AppState>) -> Result<(), String> {
let mut data = state.data.lock().map_err(|e| e.to_string())?;
data.push(item);
Ok(())
}
fn main() {
tauri::Builder::default()
.manage(AppState {
data: Mutex::new(Vec::new()),
})
.invoke_handler(tauri::generate_handler![add_item])
.run(tauri::generate_context!())
.expect("error");
}
Async Commands Blocking
Problem: UI freezes during long operations
Solution: Use async commands:
rust
#[tauri::command]
async fn long_operation() -> Result<String, String> {
tokio::time::sleep(std::time::Duration::from_secs(2)).await;
Ok("Done".to_string())
}
Window Events Not Firing
Problem: window.emit() not reaching frontend
Solution: Check event name and ensure listener is registered first:
typescript
// Frontend - set up listener BEFORE triggering backend
import { listen } from '@tauri-apps/api/event';
const unlisten = await listen('my-event', (event) => {
console.log('Received:', event.payload);
});
// Only now trigger the backend action
await invoke('start_operation');
rust
// Backend
use tauri::Manager;
#[tauri::command]
fn start_operation(app: tauri::AppHandle) {
// Emit to all windows
app.emit_all("my-event", "payload").ok();
}
File Dialog Not Working in WSL2
Problem: File dialogs crash or don't appear
Solution: Use Tauri's dialog API with workarounds:
rust
#[tauri::command]
async fn pick_file() -> Result<String, String> {
let path = tauri::api::dialog::blocking::FileDialogBuilder::new()
.pick_file()
.ok_or("No file selected")?;
Ok(path.to_string_lossy().to_string())
}
If still failing, use native Gtk dialogs or implement custom file picker.
WSL2-Specific Debugging
Check WebKitGTK Installation
bash
pkg-config --modversion webkit2gtk-4.1 # Should return version number # If missing: sudo apt install libwebkit2gtk-4.1-dev
Debug GTK Issues
bash
GTK_DEBUG=interactive cargo tauri dev
Check Display Configuration
bash
echo $DISPLAY # Should be :0 for WSLg echo $WAYLAND_DISPLAY # Should be set for WSLg # Test with simple GTK app gtk3-demo
Build Debugging
Bundle Fails
bash
# Verbose build cargo tauri build --verbose # Check target cargo tauri build --target x86_64-unknown-linux-gnu
Missing Icons
Ensure icons exist in src-tauri/icons/:
code
icons/ ├── 32x32.png ├── 128x128.png ├── 128x128@2x.png ├── icon.icns ├── icon.ico └── icon.png
AppImage Issues on WSL2
bash
# Install FUSE sudo apt install fuse libfuse2 # Or extract and run ./my-app.AppImage --appimage-extract ./squashfs-root/AppRun
Useful Commands
bash
# Run with full debug output RUST_LOG=debug RUST_BACKTRACE=1 cargo tauri dev # Build for current platform cargo tauri build # Generate TypeScript bindings (if using tauri-specta) cargo test -- --nocapture # Check Tauri CLI version cargo tauri --version # Update Tauri dependencies cargo update -p tauri -p tauri-build