{"record":{"id":"8d573e7d8b56459d","repo":"tauri-apps/tauri","slug":"failed-to-get-bundle-filename","errorCode":null,"errorMessage":"failed to get bundle filename","messagePattern":"failed to get bundle filename","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tauri-macos-sign/src/lib.rs","lineNumber":145,"sourceCode":"}\n\npub fn notarize_without_stapling(\n  keychain: &Keychain,\n  app_bundle_path: &Path,\n  auth: &AppleNotarizationCredentials,\n) -> Result<()> {\n  notarize_inner(keychain, app_bundle_path, auth, false)\n}\n\nfn notarize_inner(\n  keychain: &Keychain,\n  app_bundle_path: &Path,\n  auth: &AppleNotarizationCredentials,\n  wait: bool,\n) -> Result<()> {\n  let bundle_stem = app_bundle_path\n    .file_stem()\n    .expect(\"failed to get bundle filename\");\n\n  let tmp_dir = tempfile::tempdir().map_err(Error::TempDir)?;\n  let zip_path = tmp_dir\n    .path()\n    .join(format!(\"{}.zip\", bundle_stem.to_string_lossy()));\n  let zip_args = vec![\n    \"-c\",\n    \"-k\",\n    \"--keepParent\",\n    \"--sequesterRsrc\",\n    app_bundle_path\n      .to_str()\n      .expect(\"failed to convert bundle_path to string\"),\n    zip_path\n      .to_str()\n      .expect(\"failed to convert zip_path to string\"),\n  ];\n","sourceCodeStart":127,"sourceCodeEnd":163,"githubUrl":"https://github.com/tauri-apps/tauri/blob/52e4b6e71d8632a7e648f866c442e287ecddee34/crates/tauri-macos-sign/src/lib.rs#L127-L163","documentation":"Panic in tauri-macos-sign's notarization: app_bundle_path.file_stem().expect(\"failed to get bundle filename\") returns None only when the path has no filename component — the filesystem root, an empty path, or a path ending in `..`. notarize()/notarize_and_wait() expect a real `<Name>.app` bundle path; a degenerate path aborts before the zip step.","triggerScenarios":"Calling notarize (directly or via the tauri-cli macOS signing flow) with a path like \"/\", \"\", or one ending in `..` — typically the result of path-manipulation bugs such as one pop()/parent() too many, or joining an unset environment variable.","commonSituations":"CI scripts assembling the .app path from env vars where one is empty; glob results passed to the signer without validation; refactor of path handling in release scripts.","solutions":["Log the bundle path right before notarizing and confirm it ends in a real `<Name>.app` component","Fix the path construction: guard pop()/parent() chains, require the env var that names the .app","Validate in your wrapper: path.file_stem().is_some() and extension == \"app\" before calling the API"],"exampleFix":"// before\nlet bundle = root.join(std::env::var(\"APP_PATH\").unwrap_or_default()); // may be degenerate\nnotary.notarize(&keychain, &bundle, &auth, true)?;\n\n// after\nlet bundle = root.join(std::env::var(\"APP_PATH\").expect(\"APP_PATH unset\"));\nassert!(bundle.extension().is_some_and(|e| e == \"app\"));\nnotary.notarize(&keychain, &bundle, &auth, true)?;","handlingStrategy":"validation","validationCode":"use std::path::Path;\nfn is_app_bundle(p: &Path) -> bool {\n    p.file_stem().is_some() && p.extension().is_some_and(|e| e == \"app\")\n}\nassert!(is_app_bundle(&bundle); // before notarize()","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Validate the .app path immediately before notarizing and log it","Require (don't default) every env var used to assemble the bundle path","Avoid chains of pop()/parent() on paths feeding the signer"],"tags":["macos","notarization","path","signing"],"backgroundTag":"invalid-path-argument","analyzedSha":"52e4b6e71d8632a7e648f866c442e287ecddee34","analyzedAt":"2026-08-20T13:59:20.734Z","contentChangedAt":"2026-08-20T13:59:20.734Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}