tauri-apps/tauri · error

failed to extract merge module filename

Error message

failed to extract merge module filename

What it means

get_merge_modules iterates *.msm files in the merge-modules directory and derives each module's filename via Path::file_name(). If a matched path has no final component (ends in '..', root, or empty), file_name() returns None and the code panics with .expect("failed to extract merge module filename").

Solutions

  1. Point mergeModules at actual .msm files, not directories; remove trailing slashes and '..' components from the configured paths.
  2. Check the merge-modules directory for odd entries (dot directories, symlinks to roots) and clean them.
  3. Replace the expect with file_name().with_context(...)? or a filter_map that skips nameless paths.

Example fix

// before
let filename = path.file_name().expect("failed to extract merge module filename")
  .to_os_string().into_string().expect("failed to convert merge module filename to string");

// after
let filename = path.file_name()
  .with_context(|| format!("merge module path has no filename: {}", path.display()))?
  .to_string_lossy().into_owned();
Defensive patterns

Strategy: validation

Validate before calling

// pre-scan merge module dir
for entry in glob("**/*.msm")? {
  let p = entry?;
  if p.file_name().is_none() {
    return Err(anyhow!("bad merge module path: {}", p.display()));
  }
}

Type guard

fn has_filename(p: &std::path::Path) -> bool { p.file_name().is_some() }

Try / catch

// wrap the bundler in a subprocess; on this panic, report that a mergeModules
// path is malformed (trailing slash, '..', or a directory).

Prevention

When it happens

Trigger: Calling bundle_project with bundle.windows.wix.mergeModules entries (or the resources/resources dir containing merge modules) where a glob-expanded path lacks a file name — e.g. a glob like "dir/*" matched nothing useful or the configured path ends in a separator or '..'.

Common situations: A merge module configured as a directory instead of an .msm file, a path with a trailing slash in tauri.conf.json, or a custom glob returning '.'/'..' entries.

Related errors


AI-assisted analysis of tauri-apps/tauri@460ec35447 (2026-09-18). Data as JSON: /api/errors/fa6d08fa77816d12. Report an issue: GitHub.

Appendix: source

Thrown at crates/tauri-bundler/src/bundle/windows/msi/mod.rs:985

struct MergeModule {
  name: String,
  path: String,
}

fn get_merge_modules(settings: &Settings) -> crate::Result<Vec<MergeModule>> {
  let mut merge_modules = Vec::new();
  let regex = Regex::new(r"[^\w\d\.]")?;
  for msm in glob::glob(
    &PathBuf::from(glob::Pattern::escape(
      &settings.project_out_directory().to_string_lossy(),
    ))
    .join("*.msm")
    .to_string_lossy(),
  )? {
    let path = msm?;
    let filename = path
      .file_name()
      .expect("failed to extract merge module filename")
      .to_os_string()
      .into_string()
      .expect("failed to convert merge module filename to string");
    merge_modules.push(MergeModule {
      name: regex.replace_all(&filename, "").to_string(),
      path: path.to_string_lossy().to_string(),
    });
  }
  Ok(merge_modules)
}

/// Generates the data required for the resource bundling on wix
fn generate_resource_data(settings: &Settings) -> crate::Result<ResourceDirectory> {
  let cwd = std::env::current_dir()?;

  let mut root_resource_directory = ResourceDirectory::default();
  let mut added_resources = HashSet::new();

View on GitHub (pinned to 460ec35447)