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
- Run `plutil -lint <bundle>/Contents/Info.plist` to see the exact parse error.
- Restore a valid Info.plist — re-run the desktop build, or re-download the laufey bundle so staging starts clean.
- 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
- Treat interrupted desktop builds as poisoned: delete the staged bundle and rebuild rather than reusing it.
- Keep Info.plist generation entirely in the toolchain; never hand-edit inside a staged .app.
- In CI, checksum-verify downloaded laufey bundles when the tooling exposes hashes.
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
- codesigning requires a macOS build host (uses `codesign(1)`)
- macos.codesignIdentity is empty
- CFBundleIdentifier is empty in {}
- codesign failed for {} (identity {:?})
- helper plist {} has no CFBundleIdentifier
AI-assisted analysis of denoland/deno@f7822238ca (2026-08-20).
Data as JSON: /api/errors/8561dc3c3d2b8e53.
Report an issue: GitHub.