tauri-apps/tauri · error
Can't extract file name from path
Error message
Can't extract file name from path
What it means
This panic comes from an `.expect()` on `Path::file_name()` inside `create_zip`, which builds the Windows updater `.zip`. `file_name()` returns `None` when the source path ends in `..`, is a bare root/prefix (e.g. `/`, `C:\`), or is empty. The bundler treats this as an unrecoverable invariant: it must embed a file name in the zip archive, so it panics instead of returning an error.
Solutions
- Canonicalize the source path before bundling (`src_file.canonicalize()?` or `std::fs::canonicalize`) so `..` and relative segments are resolved and `file_name()` yields a real component
- Ensure the updater bundle path passed to tauri-bundler points to the actual artifact file, not a parent directory or root
- If constructing paths programmatically, avoid `join("..")`; use `path.parent()` to move up instead
- If you control the caller, validate `src_file.file_name().is_some()` before calling and surface a clear error
Example fix
// before
let src = PathBuf::from("/build/app/..");
create_zip(&src, &dst)?; // panics
// after
let src = PathBuf::from("/build/app").canonicalize()?;
assert!(src.is_file());
create_zip(&src, &dst)?; Defensive patterns
Strategy: validation
Validate before calling
fn ensure_file_name(p: &std::path::Path) -> Result<(), String> {
if p.file_name().is_none() {
return Err(format!("path has no file name component: {}", p.display()));
}
Ok(())
}
// call ensure_file_name(&src_file)? before create_zip Type guard
fn has_file_name(p: &std::path::Path) -> bool {
p.file_name().is_some()
} Prevention
- Canonicalize all artifact paths with std::fs::canonicalize before passing them to the bundler
- Never end paths in `..`; use parent() for directory navigation
- Assert the updater source is a regular file before bundling
- In CI, print resolved absolute paths before invoking the bundler to catch path-assembly bugs early
When it happens
Trigger: Calling `create_zip(src_file, dst_file)` with a `src_file` that has no final component: a path ending in `..` (e.g. `target/release/bundle/..`), a root path (`/` or `C:\`), or a path normalized to empty. Reached via `bundle_update_windows` during Windows updater bundle generation.
Common situations: Build scripts or config passing a directory path with a trailing `..` (often from `PathBuf::push`/`join` with `..` components), paths built from environment variables or CLI args that were never canonicalized, or programmatically constructed paths stripped down to the root.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- Path has no file_name
- Can't read source directory
- Couldn't get framework filename
- Couldn't get framework filename
- Couldn't get library filename
AI-assisted analysis of tauri-apps/tauri@460ec35447 (2026-09-18).
Data as JSON: /api/errors/e0feac977d3961a6.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tauri-bundler/src/bundle/updater_bundle.rs:211
log::info!(action = "Bundling"; "{}", display_path(&archived_path));
// Create our gzip file
create_zip(&source_path, &archived_path).with_context(|| "Failed to zip update bundle")?;
installers_archived_paths.push(archived_path);
}
Ok(installers_archived_paths)
}
pub fn create_zip(src_file: &Path, dst_file: &Path) -> crate::Result<PathBuf> {
let parent_dir = dst_file.parent().expect("No data in parent");
fs::create_dir_all(parent_dir)?;
let writer = fs_utils::create_file(dst_file)?;
let file_name = src_file
.file_name()
.expect("Can't extract file name from path");
let mut zip = zip::ZipWriter::new(writer);
let options = SimpleFileOptions::default()
.compression_method(zip::CompressionMethod::Stored)
.unix_permissions(0o755);
zip.start_file(file_name.to_string_lossy(), options)?;
let mut f =
File::open(src_file).fs_context("failed to open updater ZIP file", src_file.to_path_buf())?;
let mut buffer = Vec::new();
f.read_to_end(&mut buffer)?;
zip.write_all(&buffer)?;
buffer.clear();
Ok(dst_file.to_owned())
}
View on GitHub (pinned to 460ec35447)