tauri-apps/tauri · error · anyhow::Error

Framework path should have .framework extension: {}

Error message

Framework path should have .framework extension: {}

What it means

Entries in bundle.macOS.frameworks must be one of three shapes: a path ending in .framework (copied as a directory), a path ending in .dylib (copied as a file), or a bare framework name without '/' that is searched under the user's and system Library/Frameworks directories. An entry that contains a path separator but ends in neither extension is ambiguous and rejected before the standard-location search runs.

Source

Thrown at crates/tauri-build/src/lib.rs:191

    if framework.ends_with(".framework") {
      let src_path = Path::new(framework);
      let src_name = src_path
        .file_name()
        .expect("Couldn't get framework filename");
      let dest_path = dest_dir.join(src_name);
      copy_dir(src_path, &dest_path)?;
      continue;
    } else if framework.ends_with(".dylib") {
      let src_path = Path::new(framework);
      if !src_path.exists() {
        return Err(anyhow::anyhow!("Library not found: {}", framework));
      }
      let src_name = src_path.file_name().expect("Couldn't get library filename");
      let dest_path = dest_dir.join(src_name);
      copy_file(src_path, &dest_path)?;
      continue;
    } else if framework.contains('/') {
      return Err(anyhow::anyhow!(
        "Framework path should have .framework extension: {}",
        framework
      ));
    }
    if let Some(home_dir) = dirs::home_dir() {
      if copy_framework_from(&home_dir.join("Library/Frameworks/"), framework, dest_dir)? {
        continue;
      }
    }
    if copy_framework_from("/Library/Frameworks/".as_ref(), framework, dest_dir)?
      || copy_framework_from("/Network/Library/Frameworks/".as_ref(), framework, dest_dir)?
    {
      continue;
    }
  }
  Ok(())
}

View on GitHub (pinned to 2f1cd75b0f)

Solutions

  1. If the entry is a framework bundle, make the path end with '.framework' (e.g. vendor/MyFramework.framework)
  2. If it is a dynamically linked library, point at the '.dylib' file explicitly
  3. If the framework is installed system-wide (~/Library, /Library, /Network/Library), use its bare name with no slash so the standard locations are searched

Example fix

// before
"macOS": { "frameworks": ["vendor/Sparkle"] }

// after
"macOS": { "frameworks": ["vendor/Sparkle.framework"] }  // or just "Sparkle"
Defensive patterns

Strategy: validation

Validate before calling

// prebuild check: frameworks entries must be .framework, .dylib, or bare names
const cfg = JSON.parse(readFileSync('src-tauri/tauri.conf.json', 'utf8'))
for (const f of cfg.bundle?.macOS?.frameworks ?? []) {
  if (f.includes('/') && !f.endsWith('.framework') && !f.endsWith('.dylib')) {
    throw new Error(`invalid framework entry: ${f}`)
  }
}

Prevention

When it happens

Trigger: bundle.macOS.frameworks contains a string with at least one '/' that does not end with '.framework' or '.dylib', e.g. 'vendor/MyFramework' or '/opt/local/lib/mylib'.

Common situations: Assuming any path to a framework directory is accepted; listing a plain library path while expecting the system-search behavior that is reserved for bare names; truncated extensions from manual editing.

Related errors


AI-assisted analysis of tauri-apps/tauri@2f1cd75b0f (2026-08-16). Data as JSON: /api/errors/3793b3ad4badac25. Report an issue: GitHub.