denoland/deno · error
bundle identifier is empty
Error message
bundle identifier is empty
What it means
Thrown by validate_bundle_identifier when the identifier passed via `--identifier` is the empty string. The identifier becomes Apple's CFBundleIdentifier, the Linux .desktop filename, and the Windows AppUserModelID, so it must be a non-empty reverse-DNS string. An empty value usually comes from shell quoting eating the argument rather than from intent.
Source
Thrown at cli/tools/desktop.rs:2463
/// or silently mis-extract. Returns `None` on any read or parse failure.
fn read_plist_string(path: &Path, key: &str) -> Option<String> {
let dict: plist::Dictionary = plist::from_file(path).ok()?;
dict.get(key)?.as_string().map(|s| s.to_string())
}
/// Validate a reverse-DNS bundle identifier (Apple `CFBundleIdentifier`,
/// also used for Linux `.desktop` filenames and Windows AppUserModelID).
///
/// Apple's rules: ASCII alphanumerics, hyphens, and dots; must have at
/// least one dot (so it looks like reverse DNS); each dot-separated
/// segment must be non-empty and not start with a digit. We don't
/// enforce the segment-leading-letter rule strictly (some legacy apps
/// use digits) but we do reject empty segments and obvious shell
/// metacharacters — the identifier ends up as a `codesign` argument and
/// a path component of the helper bundles.
fn validate_bundle_identifier(id: &str) -> Result<(), AnyError> {
if id.is_empty() {
bail!("bundle identifier is empty");
}
if id.len() > 155 {
// Apple's documented limit for CFBundleIdentifier on receipts is
// 155 chars; bigger values quietly truncate elsewhere in the
// toolchain.
bail!("bundle identifier {id:?} is longer than 155 characters");
}
if !id.contains('.') {
bail!(
"bundle identifier {id:?} must be in reverse-DNS form (e.g. com.acme.foo)"
);
}
for c in id.chars() {
if !(c.is_ascii_alphanumeric() || c == '.' || c == '-') {
bail!(
"bundle identifier {id:?} must match [A-Za-z0-9.-]+, but contains {c:?}",
);
}View on GitHub (pinned to f7822238ca)
Solutions
- Provide a real reverse-DNS identifier: `--identifier com.acme.myapp`.
- In CI, verify the variable is set first: `test -n "$BUNDLE_ID" || exit 1`.
- Or omit `--identifier` to let Deno synthesize `com.deno.desktop.<app-name-slug>`.
Example fix
# before deno desktop --identifier "$BUNDLE_ID" main.ts # BUNDLE_ID unset -> "" # after export BUNDLE_ID=com.acme.myapp deno desktop --identifier "$BUNDLE_ID" main.ts
Defensive patterns
Strategy: validation
Validate before calling
# bash: refuse to pass an empty identifier
[[ -n "${BUNDLE_ID:-}" ]] || { echo "BUNDLE_ID is empty" >&2; exit 1; }
deno desktop --identifier "$BUNDLE_ID" main.ts Type guard
// TypeScript
function isNonEmptyBundleIdentifier(id: string | undefined): id is string {
return typeof id === "string" && id.length > 0;
} Prevention
- Assert required CI variables are non-empty before invoking the CLI.
- Prefer omitting --identifier over passing an empty one; Deno synthesizes a usable id.
- Set `set -u` in shell scripts so unset variables fail at expansion.
When it happens
Trigger: `deno desktop --identifier "" main.ts`; `--identifier $BUNDLE_ID` with the variable unset in the shell/CI; a config/CI pipeline templating an empty value into the flag.
Common situations: CI where the identifier secret/var is not exported for the job; a shell script with a typo'd variable name expanding to empty; copy-pasted command where the value was deleted but quotes remained.
Related errors
- bundle identifier {id:?} must be in reverse-DNS form (e.g. c
- bundle identifier {id:?} must match [A-Za-z0-9.-]+, but cont
- Invalid deep-link scheme {scheme:?}: {reason}.
- unknown --compress format '{other}' (use xz or zstd)
- bundle identifier {id:?} is longer than 155 characters
AI-assisted analysis of denoland/deno@f7822238ca (2026-08-20).
Data as JSON: /api/errors/c5fa5086568edff9.
Report an issue: GitHub.