{"record":{"id":"999441399a901717","repo":"tauri-apps/tauri","slug":"invalid-identifier-in-permission-set","errorCode":null,"errorMessage":"invalid identifier in permission set?","messagePattern":"invalid identifier in permission set\\?","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tauri-utils/src/acl/resolved.rs","lineNumber":434,"sourceCode":"\n// get the permissions from a permission set\nfn get_permission_set_permissions<'a>(\n  permission_id: &Identifier,\n  acl: &'a BTreeMap<String, Manifest>,\n  manifest: &'a Manifest,\n  set: &'a PermissionSet,\n) -> Result<Vec<TraversedPermission<'a>>, Error> {\n  let key = permission_id.get_prefix().unwrap_or(APP_ACL_KEY);\n\n  let mut permissions = Vec::new();\n\n  for perm in &set.permissions {\n    // a set could include permissions from other plugins\n    // for example `dialog:default`, could include `fs:default`\n    // in this case `perm = \"fs:default\"` which is not a permission\n    // in the dialog manifest so we check if `perm` still have a prefix (i.e `fs:`)\n    // and if so, we resolve this prefix from `acl` first before proceeding\n    let id = Identifier::try_from(perm.clone()).expect(\"invalid identifier in permission set?\");\n    let (manifest, permission_id, key, permission_name) =\n      if let Some((new_key, manifest)) = id.get_prefix().and_then(|k| acl.get(k).map(|m| (k, m))) {\n        (manifest, &id, new_key, id.get_base())\n      } else {\n        (manifest, permission_id, key, perm.as_str())\n      };\n\n    if permission_name == \"default\" {\n      permissions.extend(\n        manifest\n          .default_permission\n          .as_ref()\n          .map(|default| get_permission_set_permissions(permission_id, acl, manifest, default))\n          .transpose()?\n          .unwrap_or_default(),\n      );\n    } else if let Some(permission) = manifest.permissions.get(permission_name) {\n      permissions.push(TraversedPermission {","sourceCodeStart":416,"sourceCodeEnd":452,"githubUrl":"https://github.com/tauri-apps/tauri/blob/52e4b6e71d8632a7e648f866c442e287ecddee34/crates/tauri-utils/src/acl/resolved.rs#L416-L452","documentation":"Panic during ACL resolution while expanding a permission set: each entry is parsed with Identifier::try_from(perm.clone()).expect(\"invalid identifier in permission set?\"). Identifiers must be non-empty lowercase ASCII with hyphens (not leading/trailing), at most one `:` separator, a non-empty base after the prefix, and must not start with `tauri-plugin`. Any entry violating these rules (\"\", \"fs:\", \"a:b:c\", \"Camel\", \"-x\") aborts the build.","triggerScenarios":"A permission set in a plugin manifest or app-level permissions file whose `permissions` array contains a malformed reference — empty string, prefix without base (`fs:`), double separator, uppercase/invalid characters, or a `tauri-plugin*` prefix.","commonSituations":"Hand-writing permissions/*.toml for a plugin; scripts that generate permission files and emit empty strings for missing commands; copy-paste typos like `core:window:default:` or `Shell:default`.","solutions":["Locate the failing set — the panic happens while resolving the set named just above in the build log; open that plugin's or app's permissions file","Fix entries to `plugin-name:permission-name` or bare `permission-name`: lowercase, single optional colon, no leading/trailing hyphen, never starting with `tauri-plugin`","Add a unit test that runs each set entry through tauri_utils::acl::Identifier::try_from to surface real parse errors","cargo clean and rebuild after fixing the manifest"],"exampleFix":"# permissions/sets.toml — before\n[[set]]\npermissions = [\"fs:\", \"Core:default\"]\n\n# after\n[[set]]\npermissions = [\"fs:default\", \"core:default\"]","handlingStrategy":"type-guard","validationCode":"// run in CI over every permission-set entry read from permissions/*.toml\nfor perm in set_entries {\n    assert!(is_valid_permission_id(&perm), \"bad identifier: {perm}\");\n}","typeGuard":"pub fn is_valid_permission_id(s: &str) -> bool {\n    tauri_utils::acl::Identifier::try_from(s.to_string()).is_ok()\n}","tryCatchPattern":null,"preventionTips":["Unit-test permission-set manifests so Identifier::try_from reports real parse errors instead of the build panicking","Generate permission files with templates that never emit empty entries","Follow the plugin-name:permission-name form: lowercase, one colon max, no leading/trailing hyphen, no tauri-plugin prefix"],"tags":["acl","permissions","identifier","validation"],"backgroundTag":"invalid-acl-identifier","analyzedSha":"52e4b6e71d8632a7e648f866c442e287ecddee34","analyzedAt":"2026-08-20T13:59:20.734Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}