All tests run on an 8-year-old MacBook Air. All results from shipping 7 Mac apps as a solo developer. No sponsored opinion.
The most common Tauri v2 frustration: you write a command, invoke it from the frontend, and nothing happens. No error. No crash. Just silence. It's almost always permissions.
How Tauri v2 permissions work
Tauri v2 introduced a capability system. Every plugin action — reading files, executing shell commands, sending notifications — requires an explicit permission declaration in your config. Without the permission, the plugin call fails silently on the frontend. The Rust code never runs.
// src-tauri/capabilities/main.json
{
"identifier": "main-capability",
"description": "Permissions for main window",
"windows": ["main"],
"permissions": [
"core:default",
"fs:read-all",
"fs:write-all",
"shell:allow-execute",
"opener:allow-open",
"global-shortcut:allow-register",
"global-shortcut:allow-unregister"
]
}
Note: As of Tauri v2.1,
shell:allow-openis deprecated. Usetauri-plugin-openerandopener:allow-openinstead.
The debugging flow
When a command does nothing:
-
Open DevTools (
Cmd+Option+Iin dev mode) — check the console for a rejected Promise or permission error -
Check your terminal output — the Rust side logs errors directly in the
tauri devterminal; look for lines like[tauri] permission deniedornot allowed -
Enable verbose logging — set
RUST_LOG=tauri=debugbefore runningtauri devfor more detailed backend output - Check your capabilities file — missing or misspelled permission identifiers are the #1 cause
Permission errors in the console typically look like a rejected Promise with a message such as plugin:shell|execute not allowed. The capabilities file is always the first thing to check.
Common permissions you'll need
"permissions": [
"core:default",
"fs:read-all", // read any file
"fs:write-all", // write any file
{
"identifier": "shell:allow-execute",
"allow": [{ "name": "my-cmd", "cmd": "adb", "args": true }]
},
"opener:allow-open", // open URLs / files (replaces shell:allow-open)
"path:allow-app-data-dir", // access app data directory
"notification:default", // send notifications
"global-shortcut:allow-register",
"clipboard-manager:allow-read-text",
"clipboard-manager:allow-write-text"
]
shell:allow-executenow requires an explicit allow scope — wildcards are blocked by default for security.
The scope system
For filesystem access, Tauri supports scoped permissions — allow access only to specific directories:
{
"identifier": "fs:allow-app-data-read",
"allow": [{ "path": "$APPDATA/**" }]
}
Use scoped permissions in production. fs:read-all is convenient for development, but shipping with it exposes more than needed.
The verdict
Tauri v2's permission system is correct. The sandboxing is good for security. The silent failure mode is painful until you know the pattern. When something stops working after a plugin update, always check whether the permission identifiers have changed — opener replacing shell:allow-open is a real example of this happening.
Check the capabilities file first. Always.
If this was useful, a ❤️ helps more than you'd think — thanks!
Hiyoko PDF Vault → https://hiyokomtp.lemonsqueezy.com/checkout/buy/a1b4d7d8-a4b8-433c-9d36-abdc0f3937c3
X → @hiyoyok
Top comments (1)
TL;DR: Silent failures in Tauri v2 are almost always a missing permission in your capabilities file. Check DevTools console first — the rejected Promise message tells you exactly which permission you need.