{"record":{"id":"a61bc07dda2b2ae9","repo":"tauri-apps/tauri","slug":"permission-not-found-expected-one-of","errorCode":null,"errorMessage":"Permission {} not found, expected one of {}","messagePattern":"Permission (.+?) not found, expected one of (.+?)","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/tauri-build/src/acl.rs","lineNumber":388,"sourceCode":"        let mut available_permissions = Vec::new();\n        for (key, manifest) in acl_manifests {\n          let prefix = if key == APP_ACL_KEY {\n            \"\".to_string()\n          } else {\n            format!(\"{key}:\")\n          };\n          if manifest.default_permission.is_some() {\n            available_permissions.push(format!(\"{prefix}default\"));\n          }\n          for p in manifest.permissions.keys() {\n            available_permissions.push(format!(\"{prefix}{p}\"));\n          }\n          for p in manifest.permission_sets.keys() {\n            available_permissions.push(format!(\"{prefix}{p}\"));\n          }\n        }\n\n        anyhow::bail!(\n          \"Permission {} not found, expected one of {}\",\n          permission_id.get(),\n          available_permissions.join(\", \")\n        );\n      }\n    }\n  }\n\n  Ok(())\n}\n\npub fn build(out_dir: &Path, target: Target, attributes: &Attributes) -> super::Result<()> {\n  let mut acl_manifests = read_plugins_manifests()?;\n\n  let app_acl = app_manifest_permissions(\n    out_dir,\n    attributes.app_manifest,\n    &attributes.inlined_plugins,","sourceCodeStart":370,"sourceCodeEnd":406,"githubUrl":"https://github.com/tauri-apps/tauri/blob/2f1cd75b0f3fb72e6870d719bbfeadedcf8ca884/crates/tauri-build/src/acl.rs#L370-L406","documentation":"During tauri-build, every permission identifier referenced by a capability file (src-tauri/capabilities/*.json) is validated against the ACL manifests gathered from the application and its plugins. An identifier is resolved as <prefix>:<base>; the app's own ACL is the empty prefix. If the prefix is unknown or the base name is not a permission/permission-set in that manifest (with 'default' always accepted), the build fails and enumerates every permission that IS available.","triggerScenarios":"Building or running a Tauri v2 app (cargo build / tauri dev) whose capabilities/*.json references an unknown permission: a typo (fs:allow-readf), a wrong prefix (shell-open instead of shell:allow-open), a permission from a plugin not present in Cargo.toml, or a permission renamed/removed in a plugin upgrade. Capabilities are only validated for the target being built, so platform-filtered files check on their target.","commonSituations":"Copy-pasting capability snippets from docs of a different plugin major version; removing a plugin dependency but leaving its capability entries behind; renaming permissions across plugin upgrades; hand-writing permissions instead of using tauri add.","solutions":["Read the error output - it lists every available permission; correct the offending identifier in src-tauri/capabilities/*.json to one of them","If the permission should exist, add or update the plugin crate in src-tauri/Cargo.toml (e.g. tauri-plugin-fs) so its ACL manifest is collected","If the plugin was removed on purpose, delete its permission entries from the capability files","Re-run tauri dev / tauri build after the fix to re-validate"],"exampleFix":"// before: src-tauri/capabilities/main.json\n{ \"permissions\": [\"fs:allow-readfile\"] }\n\n// after\n{ \"permissions\": [\"fs:allow-read-file\"] }","handlingStrategy":"validation","validationCode":"// prebuild check: dump every permission id used by capabilities\nconst { readdirSync, readFileSync } = require('fs')\nfor (const f of readdirSync('src-tauri/capabilities')) {\n  const c = JSON.parse(readFileSync(`src-tauri/capabilities/${f}`, 'utf8'))\n  for (const p of c.permissions) console.log(f, typeof p === 'string' ? p : p.identifier)\n}\n// cross-check each '<plugin>:<name>' against that plugin's permissions/ folder or docs before building","typeGuard":null,"tryCatchPattern":null,"preventionTips":["After adding or removing a plugin, grep capabilities/*.json for its '<plugin>:' prefix and clean stale entries","Prefer `tauri add <plugin>` so dependency and capability are written together","Read plugin changelogs when upgrading majors - permissions get renamed","Treat the error's available-permissions list as the source of truth when fixing identifiers"],"tags":["acl","capabilities","permissions","tauri-build","config"],"backgroundTag":null,"analyzedSha":"2f1cd75b0f3fb72e6870d719bbfeadedcf8ca884","analyzedAt":"2026-08-16T04:18:42.486Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}