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

  1. Validate Info.plist with `plutil -lint src-tauri/Info.plist` and fix the reported XML/syntax errors
  2. Ensure the file is XML plist format, not binary (convert with `plutil -convert xml1 Info.plist`)
  3. Check file read permissions for the build process
  4. Temporarily rename/delete Info.plist to confirm it is the cause; recreate it from a known-good template
  5. 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

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


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)