tauri-apps/tauri · error
failed to read plist
Error message
failed to read plist {}: {} What it means
This panic occurs at build time in tauri-codegen when the macOS Info.plist file exists but cannot be parsed as a plist. The codegen step reads Info.plist from the config parent directory to inject isolation-related entries (e.g. bundle name) into the embedded asset context. A malformed, corrupt, or unreadable plist aborts the Rust macro expansion.
Solutions
- Validate Info.plist with `plutil -lint src-tauri/Info.plist` and fix the reported XML/syntax errors
- Ensure the file is XML plist format, not binary (convert with `plutil -convert xml1 Info.plist`)
- Check file read permissions for the build process
- Temporarily rename/delete Info.plist to confirm it is the cause; recreate it from a known-good template
- Update tauri-codegen and the plist crate in case of a parser bug
Example fix
// before (broken plist) <?xml version="1.0"?><plist version="1.0"><dict><key>CFBundleName</key></dict></plist> // after (valid plist) <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"><dict><key>CFBundleName</key><string>MyApp</string></dict></plist>
Defensive patterns
Strategy: validation
Validate before calling
import subprocess, sys
r = subprocess.run(['plutil', '-lint', 'src-tauri/Info.plist'], capture_output=True, text=True)
if r.returncode != 0:
sys.exit(f'Invalid plist: {r.stdout}') Type guard
const isXmlPlist = (s: string) => s.trimStart().startsWith('<?xml') && s.includes('<plist'); Prevention
- Lint Info.plist in CI with plutil -lint before building
- Keep Info.plist in XML format and under version control with CI diff checks
- Validate after every manual edit with plutil
When it happens
Trigger: Building a Tauri v2 project for macOS in dev mode (not tests) where src-tauri/Info.plist exists but plist::Value::from_file fails: invalid XML syntax, wrong encoding, binary plist format not supported, or the file is unreadable.
Common situations: Hand-edited Info.plist with broken XML; a placeholder/empty Info.plist file; a binary-format plist generated by Xcode; file permission problems; committing a truncated plist to the repo.
Related errors
- failed to serialize plist
- No file name
- not implemented
- Couldn't get framework filename
- Couldn't get framework filename
AI-assisted analysis of tauri-apps/tauri@460ec35447 (2026-09-18).
Data as JSON: /api/errors/3f2ef7249d1845be.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tauri-codegen/src/context.rs:306
let with_tray_icon_code = if target.is_desktop() {
if let Some(tray) = &config.app.tray_icon {
let tray_icon_icon_path = config_parent.join(&tray.icon_path);
let icon = CachedIcon::new(&root, &tray_icon_icon_path)?;
quote!(context.set_tray_icon(::std::option::Option::Some(#icon));)
} else {
quote!()
}
} else {
quote!()
};
#[cfg(target_os = "macos")]
let maybe_embed_plist_block = if target == Target::MacOS && dev && !running_tests {
let info_plist_path = config_parent.join("Info.plist");
let mut info_plist = if info_plist_path.exists() {
plist::Value::from_file(&info_plist_path)
.unwrap_or_else(|e| panic!("failed to read plist {}: {}", info_plist_path.display(), e))
} else {
plist::Value::Dictionary(Default::default())
};
if let Some(plist) = info_plist.as_dictionary_mut() {
if let Some(bundle_name) = config
.bundle
.macos
.bundle_name
.as_ref()
.or(config.product_name.as_ref())
{
plist.insert("CFBundleName".into(), bundle_name.as_str().into());
}
if let Some(version) = &config.version {
let bundle_version = &config.bundle.macos.bundle_version;
plist.insert("CFBundleShortVersionString".into(), version.clone().into());View on GitHub (pinned to 460ec35447)