{"record":{"id":"5f1af45659f4dfd0","repo":"tauri-apps/tauri","slug":"failed-to-read-resource-file-name","errorCode":null,"errorMessage":"failed to read resource file name","messagePattern":"failed to read resource file name","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tauri-bundler/src/bundle/windows/msi/mod.rs","lineNumber":1023,"sourceCode":"    // In some glob resource paths like `assets/**/*` a file might appear twice\n    // because the `tauri_utils::resources::ResourcePaths` iterator also reads a directory\n    // when it finds one. So we must check it before processing the file.\n    if added_resources.contains(&resource_path) {\n      continue;\n    }\n    added_resources.insert(resource_path.clone());\n\n    if settings.windows().can_sign() && should_sign(&resource_path)? {\n      try_sign(&resource_path, settings)?;\n    }\n\n    let resource_entry = ResourceFile::new(\n      resource_path,\n      Some(\n        resource\n          .target()\n          .file_name()\n          .expect(\"failed to read resource file name\")\n          .to_string_lossy()\n          .into_owned(),\n      ),\n    );\n\n    let target_path = resource.target();\n    let components_count = target_path.components().count();\n    let directories = target_path\n      .components()\n      .take(components_count - 1) // the last component is the file\n      .collect::<Vec<_>>();\n\n    let mut directory_entry = &mut root_resource_directory;\n\n    for directory in directories {\n      let directory_name = directory\n        .as_os_str()\n        .to_os_string()","sourceCodeStart":1005,"sourceCodeEnd":1041,"githubUrl":"https://github.com/tauri-apps/tauri/blob/52e4b6e71d8632a7e648f866c442e287ecddee34/crates/tauri-bundler/src/bundle/windows/msi/mod.rs#L1005-L1041","documentation":"While building an MSI installer, the bundler walks every configured resource's target path and calls Path::file_name() to derive the file name that WiX will register. file_name() returns None when the path terminates in '..' or is otherwise a path with no final component, and this expect() turns that None into a panic. So the error means a resources entry in tauri.conf.json has a target whose last component is not a real file name.","triggerScenarios":"Running `tauri build` (or `cargo tauri build`) with the MSI bundle target on Windows, where bundle > resources contains an entry whose target path ends in '..' (e.g. {\"src\": \"assets/x.png\", \"target\": \"stuff/..\"}) or is a root-like path with no file component. The MSI path calls resource.target().file_name() at crates/tauri-bundler/src/bundle/windows/msi/mod.rs:1023; the NSIS path handles targets differently, so this only panics for MSI/WiX builds.","commonSituations":"Typos in the resources map such as a target of \"data/..\" or \"\"; using a glob-expanded resource whose computed target collapses to a directory-level path; copying a resources config from a script that accidentally appends '/..' or strips the file name.","solutions":["Check every entry in build > resources in tauri.conf.json and make sure each target path ends with a concrete file name (or is a plain glob whose targets keep their file names).","Remove trailing '/..' or '/' components from target values; a target must name a file, not a directory traversal.","If you intended a whole directory, list it as a single source without a remapping target, or enumerate its files so each target ends in a file name.","Re-run `tauri build --bundles msi` to confirm the panic is gone."],"exampleFix":"// tauri.conf.json — before\n\"resources\": { \"assets/icon.png\": \"icons/..\" }\n\n// after\n\"resources\": { \"assets/icon.png\": \"icons/icon.png\" }","handlingStrategy":"validation","validationCode":"// Before building, validate every resources target ends in a file name\nfn valid_targets(resources: &serde_json::Value) -> bool {\n    match resources {\n        serde_json::Value::Array(items) => items.iter().all(|v| {\n            v.as_str().map(|s| Path::new(s).file_name().is_some()).unwrap_or(false)\n        }),\n        serde_json::Value::Object(map) => map.values().all(|v| {\n            v.as_str().map(|s| Path::new(s).file_name().is_some()).unwrap_or(false)\n        }),\n        _ => true,\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never end a resources target with '..' or '/'; always name the destination file explicitly.","Add a config-lint step in CI that parses tauri.conf.json and asserts every resources target has a final file-name component.","Prefer plain glob sources unless you truly need remapping; unremapped resources keep their file names automatically."],"tags":["tauri","msi","bundler","resources","path-validation","panic"],"backgroundTag":"invalid-path-in-config","analyzedSha":"52e4b6e71d8632a7e648f866c442e287ecddee34","analyzedAt":"2026-08-20T13:59:20.734Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}