denoland/deno · error

plutil could not read CFBundleIdentifier from {}: {}

Error message

plutil could not read CFBundleIdentifier from {}: {}

What it means

read_bundle_identifier runs `plutil -extract CFBundleIdentifier raw -o - <bundle>/Contents/Info.plist` and bails when plutil exits non-zero, including plutil's stderr in the message. plutil fails this way when the plist is missing, malformed/truncated, or the CFBundleIdentifier key is absent — the .app bundle is not in a readable state.

Source

Thrown at cli/tools/desktop.rs:2688

  let browser_entitlements = locate_browser_entitlements(app_bundle);
  codesign_one(app_bundle, identity, browser_entitlements.as_deref(), None)?;
  Ok(())
}

/// Read `CFBundleIdentifier` out of `Contents/Info.plist` via `plutil`.
fn read_bundle_identifier(app_bundle: &Path) -> Result<String, AnyError> {
  let plist = app_bundle.join("Contents/Info.plist");
  let output = std::process::Command::new("plutil")
    .arg("-extract")
    .arg("CFBundleIdentifier")
    .arg("raw")
    .arg("-o")
    .arg("-")
    .arg(&plist)
    .output()
    .context("failed to invoke plutil(1) to read CFBundleIdentifier")?;
  if !output.status.success() {
    bail!(
      "plutil could not read CFBundleIdentifier from {}: {}",
      plist.display(),
      String::from_utf8_lossy(&output.stderr).trim(),
    );
  }
  let id = String::from_utf8_lossy(&output.stdout).trim().to_string();
  if id.is_empty() {
    bail!("CFBundleIdentifier is empty in {}", plist.display());
  }
  Ok(id)
}

/// Cheap Mach-O sniff: a Mach-O file starts with one of the well-known
/// magic numbers (32-bit, 64-bit, fat — both endians). Used to skip
/// non-binaries inside `Contents/MacOS/` (shell launchers, update
/// sentinels) before passing them to `codesign(1)`, which would reject
/// them and abort the signing pass.
fn is_macho_file(path: &Path) -> bool {

View on GitHub (pinned to f7822238ca)

Solutions

  1. Run `plutil -lint <bundle>/Contents/Info.plist` to see the exact parse error.
  2. Restore a valid Info.plist — re-run the desktop build, or re-download the laufey bundle so staging starts clean.
  3. Confirm the plist actually contains a CFBundleIdentifier key (plutil errors on extracting a missing key).
Defensive patterns

Strategy: try-catch

Validate before calling

# Before building/signing, verify the plist parses
plutil -lint "$APP_BUNDLE/Contents/Info.plist"
plutil -extract CFBundleIdentifier raw -o - "$APP_BUNDLE/Contents/Info.plist" >/dev/null || echo "missing CFBundleIdentifier"

Try / catch

// In build scripts that call read-plist-equivalent steps
deno desktop ... || {
  echo "bundle assembly failed — check Info.plist warnings above";
  exit 1;
}

Prevention

When it happens

Trigger: The app bundle's Contents/Info.plist is corrupt or truncated (interrupted copy, disk-full during staging), the CFBundleIdentifier key was removed, or the directory being processed isn't a real .app bundle. Reached from codesigning and helper-rebinding flows that call read_bundle_identifier.

Common situations: A partially downloaded/mirrored laufey.app or a bundle mangled by manual plist edits; aggressive antivirus/backup tools altering files inside the bundle; a previous build step crashed mid-copy.

Related errors


AI-assisted analysis of denoland/deno@f7822238ca (2026-08-20). Data as JSON: /api/errors/8561dc3c3d2b8e53. Report an issue: GitHub.