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
- If the entry is a framework bundle, make the path end with '.framework' (e.g. vendor/MyFramework.framework)
- If it is a dynamically linked library, point at the '.dylib' file explicitly
- 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
- Memorize the three valid shapes: .framework path, .dylib path, bare name
- Use system frameworks by bare name so tauri-build searches standard locations
- Validate the frameworks array in a config lint step
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
- Library not found: {}
- Permission {} not found, expected one of {}
- {:?} does not exist
- {:?} is not a file
- `{}` not found; required for generating a Windows Resource f
AI-assisted analysis of tauri-apps/tauri@2f1cd75b0f (2026-08-16).
Data as JSON: /api/errors/3793b3ad4badac25.
Report an issue: GitHub.