tauri-apps/tauri · error
failed to resolve ACL
Error message
failed to resolve ACL
What it means
Thrown at build time when `Resolved::resolve` fails to combine the plugin ACL manifests and parsed capabilities into a resolved ACL for the build target. The `.expect` fires when capabilities reference unknown plugins/permissions, or the manifests and capabilities are mutually inconsistent (e.g. a permission listed in a capability does not exist in any manifest).
Solutions
- Check the compiler output above the panic for the specific unresolved permission/identifier and fix the capabilities/*.toml|json entry.
- Remove or update capabilities referencing plugins you no longer include.
- Update permission names to match the installed plugin versions (see plugin docs for renames).
- Clean the build dir (`cargo clean`) so stale manifests from removed plugins are regenerated.
- Verify custom permissions/permissions files are properly registered in build.rs / tauri.conf.json.
Example fix
// capabilities/default.json before
{"permissions": ["fs:allow-read-file", "old-plugin:do-thing"]}
// after (plugin removed)
{"permissions": ["fs:allow-read-file"]} Defensive patterns
Strategy: validation
Validate before calling
// before building, verify every permission in capabilities exists in installed plugin manifests
const caps = JSON.parse(require('fs').readFileSync('src-tauri/capabilities/default.json', 'utf8'));
const pkg = JSON.parse(require('fs').readFileSync('src-tauri/Cargo.toml', 'utf8')); // or parse properly
for (const perm of caps.permissions) {
const plugin = perm.split(':')[0];
if (plugin !== 'core' && !permImplementedByInstalledPlugin(plugin, perm)) {
console.error(`capability references unknown permission: ${perm}`);
}
} Prevention
- Update capabilities whenever you add/remove/upgrade a plugin
- Check plugin changelogs for permission renames before upgrading
- Run `cargo tauri dev` early after dependency changes to catch ACL issues
- Keep capabilities files minimal — only permissions you actually use
When it happens
Trigger: `tauri build`/`tauri dev` where a capability references a plugin permission that is not present in the resolved manifest map, plugins were removed/renamed but capabilities still reference them, or the additional capabilities files are invalid for the target.
Common situations: Upgrading Tauri or removing a plugin without updating capabilities files; typos in permission names; plugin renamed permissions between versions; referencing app-defined permissions not yet registered.
Understand the failure class
Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.
Related errors
- Permission not found, expected one of
- failed to parse capabilities
- Could not find a capability to update
- Couldn't find capabilities directory at
- embedded file asset has no parent
AI-assisted analysis of tauri-apps/tauri@460ec35447 (2026-09-18).
Data as JSON: /api/errors/26591bb17a5ce447.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tauri-codegen/src/context.rs:419
Default::default()
};
let capabilities_file_path = out_dir.join(CAPABILITIES_FILE_NAME);
let capabilities_from_files = if capabilities_file_path.exists() {
let capabilities_json =
std::fs::read_to_string(&capabilities_file_path).expect("failed to read capabilities");
serde_json::from_str(&capabilities_json).expect("failed to parse capabilities")
} else {
Default::default()
};
let capabilities = get_capabilities(
&config,
capabilities_from_files,
additional_capabilities.as_deref(),
)
.unwrap();
let resolved = Resolved::resolve(&acl, capabilities, target).expect("failed to resolve ACL");
let acl_tokens = map_lit(
quote! { ::std::collections::BTreeMap },
&acl,
str_lit,
identity,
);
let runtime_authority = quote!(#root::runtime_authority!(#acl_tokens, #resolved));
let plugin_global_api_scripts = if config.app.with_global_tauri {
if let Some(scripts) = tauri_utils::plugin::read_global_api_scripts(&out_dir) {
let scripts = scripts.into_iter().map(|s| quote!(#s));
quote!(::std::option::Option::Some(&[#(#scripts),*]))
} else {
quote!(::std::option::Option::None)
}
} else {View on GitHub (pinned to 460ec35447)