tauri-apps/tauri · error

failed to resolve ACL

Error message

failed to resolve ACL

What it means

Build-time panic in tauri-codegen when merging the ACL: Resolved::resolve(&acl, capabilities, target).expect("failed to resolve ACL") fails when the app's capabilities cannot be resolved against the plugin manifests in acl-manifests.json — typically a permission that no manifest defines, an unknown permission-set entry, or permission scoping (platform/target/remote rules) that cannot be satisfied.

Source

Thrown at crates/tauri-codegen/src/context.rs:417

    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 52e4b6e71d)

Solutions

  1. Read the full build log just above the panic — Tauri names the exact capability and permission that failed to resolve
  2. Check every permission listed in src-tauri/capabilities/*.json against the plugin's permissions/ folder (or its docs) and fix typos, renames, and removed permissions
  3. Confirm the plugin providing each permission is still a dependency: `cargo tree | grep <plugin>`
  4. cargo clean after adding/removing plugins so acl-manifests.json is regenerated
  5. Verify each capability's `platforms`/`windows` fields are consistent with the permissions used

Example fix

// src-tauri/capabilities/default.json — before
"permissions": ["core:webview:defualt"]

// after
"permissions": ["core:webview:default"]
Defensive patterns

Strategy: validation

Validate before calling

// CI unit test: resolve the ACL with real error messages instead of a codegen panic
#[test]
fn acls_resolve() {
    let acl = read_acl_manifests();          // parse OUT_DIR/acl-manifests.json
    let caps = read_capabilities();          // parse OUT_DIR/capabilities.json
    tauri_utils::acl::resolved::Resolved::resolve(&acl, caps, target)
        .expect("ACL resolution must succeed — the panic in codegen hides this error");
}

Prevention

When it happens

Trigger: A capability file in src-tauri/capilities/*.json listing a permission identifier that does not exist (typo), a permission of a plugin removed from Cargo.toml, a permission with scope/remote-url constraints that conflict with the capability, or a stale acl-manifests.json after adding/removing plugins without a clean rebuild.

Common situations: Copying a capability file from another project whose plugin set differs; upgrading a plugin that renamed/removed a permission; typos like `core:webview:defualt`; adding a plugin but building against a cached manifest map.

Related errors


AI-assisted analysis of tauri-apps/tauri@52e4b6e71d (2026-08-20). Data as JSON: /api/errors/26591bb17a5ce447. Report an issue: GitHub.