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

  1. 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
  2. Ensure the updater bundle path passed to tauri-bundler points to the actual artifact file, not a parent directory or root
  3. If constructing paths programmatically, avoid `join("..")`; use `path.parent()` to move up instead
  4. 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

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


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)