tauri-apps/tauri · critical
Couldn't get library filename
Error message
Couldn't get library filename
What it means
In tauri-build's copy_frameworks, a `.dylib` entry that exists on disk is copied by joining its `file_name()` to the destination directory. If the dylib path lacks a final component (root, trailing separator, `..`), file_name() returns None and the expect panics. Since existence was already checked, this only happens for structurally malformed paths that nonetheless resolve oddly (or races replaced the path).
Solutions
- Ensure the dylib entry in tauri.conf.json ends with the actual file name, e.g. `libs/libfoo.dylib`.
- Strip `..` and trailing separators; use a canonical absolute path.
- Check that the file (not a directory) exists at that exact path.
- Fail fast in your build script: `assert!(p.is_file() && p.file_name().is_some())` before try_build.
Example fix
// before "frameworks": ["/usr/local/lib/"] // after "frameworks": ["/usr/local/lib/libmylib.dylib"]
Defensive patterns
Strategy: validation
Validate before calling
let p = std::path::Path::new("libs/libmylib.dylib");
assert!(p.is_file() && p.file_name().is_some(), "dylib path invalid: {}", p.display()); Type guard
fn valid_dylib(p: &std::path::Path) -> bool {
p.file_name().is_some() && p.is_file() && p.extension().map_or(false, |e| e == "dylib")
} Prevention
- Check with is_file(), not exists(), so directories and dangling links are rejected.
- Canonicalize generated paths before placing them in tauri.conf.json.
- Keep dylib entries generated by a single, tested script.
When it happens
Trigger: tauri_build::try_build with Attributes::copy_frameworks containing a `.dylib` path such as `/path/to/..` or ending in `/` that still passes the `exists()` check but yields no filename.
Common situations: Paths assembled from environment variables where the dylib name was dropped; using a directory that happens to end in `.dylib` is impossible but a symlink or `..`-based path can slip through the exists() check.
Understand the failure class
Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.
Related errors
- Couldn't get framework filename
- Couldn't get library filename
- Couldn't get framework filename
- failed to extract external binary filename
- No data in parent
AI-assisted analysis of tauri-apps/tauri@460ec35447 (2026-09-18).
Data as JSON: /api/errors/6a59080625f08273.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tauri-build/src/lib.rs:186
// Copies the macOS application bundle frameworks to the target folder
fn copy_frameworks(dest_dir: &Path, frameworks: &[String]) -> Result<()> {
fs::create_dir_all(dest_dir)
.with_context(|| format!("Failed to create frameworks output directory at {dest_dir:?}"))?;
for framework in frameworks.iter() {
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;View on GitHub (pinned to 460ec35447)