tauri-apps/tauri · error

invalid permission identifier

Error message

invalid permission identifier '{permission}'

What it means

CapabilityBuilder::permission pushes a permission reference into a capability being built. The string is converted into a `PermissionEntry::PermissionRef` identifier via TryFrom; if the string is not a valid permission identifier, the builder panics rather than producing a capability with a malformed permission.

Solutions

  1. Use a valid permission identifier string (e.g. `"core:default"`, `"fs:allow-read"`) matching the `plugin-or-core:permission` grammar.
  2. Prefer the manifest-generated constants where available instead of hand-typed strings to avoid typos.
  3. Validate the identifier before building: attempt `permission.try_into()` (the same TryInto used internally) and handle the Err.
  4. For user-supplied permission lists, parse/validate all entries before constructing the CapabilityBuilder.

Example fix

// before
let perms = std::env::var("PERMS").unwrap_or_default();
let cap = CapabilityBuilder::new("main").permission(perms); // panics on empty string
// after
let perms = std::env::var("PERMS").unwrap_or_default();
let mut cap = CapabilityBuilder::new("main");
for p in perms.split(',') {
  if let Ok(id) = p.trim().to_string().try_into() {
    cap = cap.permission(id);
  } else {
    eprintln!("skipping invalid permission: {p}");
  }
}
Defensive patterns

Strategy: validation

Validate before calling

fn is_valid_permission(s: &str) -> bool {
  !s.is_empty()
    && s.parse::<tauri::ipc::CapabilityFilePermissionIdentifier>() .is_ok()
}
// or generically: let Ok(id) = permission.clone().try_into() else { return Err(...) };

Prevention

When it happens

Trigger: Calling `.permission("...")` with a string that fails the identifier conversion — e.g. empty string, invalid characters, or a name not shaped like `plugin:permission-name` / valid set-name.

Common situations: Typo'd permission names in capability DSL code, concatenating identifiers dynamically and producing empty/invalid strings, using bare plugin names without the `plugin:` prefix when required by the identifier grammar.

Understand the failure class

Background: "invalid id" errors: invalid identifier format — why libraries reject IDs before lookup, and how to fix them — this error's family across 37 libraries.

Related errors


AI-assisted analysis of tauri-apps/tauri@460ec35447 (2026-09-18). Data as JSON: /api/errors/03d550cd61c5dcbb. Report an issue: GitHub.

Appendix: source

Thrown at crates/tauri/src/ipc/capability_builder.rs:95

  }

  /// Link this capability to the a list of window labels.
  pub fn webviews(mut self, webviews: impl IntoIterator<Item = impl Into<String>>) -> Self {
    self
      .0
      .webviews
      .extend(webviews.into_iter().map(|w| w.into()));
    self
  }

  /// Add a new permission to this capability.
  pub fn permission(mut self, permission: impl Into<String>) -> Self {
    let permission = permission.into();
    self.0.permissions.push(PermissionEntry::PermissionRef(
      permission
        .clone()
        .try_into()
        .unwrap_or_else(|_| panic!("invalid permission identifier '{permission}'")),
    ));
    self
  }

  /// Add a new scoped permission to this capability.
  pub fn permission_scoped<T: Serialize>(
    mut self,
    permission: impl Into<String>,
    allowed: Vec<T>,
    denied: Vec<T>,
  ) -> Self {
    let permission = permission.into();
    let identifier = permission
      .clone()
      .try_into()
      .unwrap_or_else(|_| panic!("invalid permission identifier '{permission}'"));

    let allowed_scope = allowed

View on GitHub (pinned to 460ec35447)