{"record":{"id":"c5fa5086568edff9","repo":"denoland/deno","slug":"bundle-identifier-is-empty","errorCode":null,"errorMessage":"bundle identifier is empty","messagePattern":"bundle identifier is empty","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cli/tools/desktop.rs","lineNumber":2463,"sourceCode":"/// or silently mis-extract. Returns `None` on any read or parse failure.\nfn read_plist_string(path: &Path, key: &str) -> Option<String> {\n  let dict: plist::Dictionary = plist::from_file(path).ok()?;\n  dict.get(key)?.as_string().map(|s| s.to_string())\n}\n\n/// Validate a reverse-DNS bundle identifier (Apple `CFBundleIdentifier`,\n/// also used for Linux `.desktop` filenames and Windows AppUserModelID).\n///\n/// Apple's rules: ASCII alphanumerics, hyphens, and dots; must have at\n/// least one dot (so it looks like reverse DNS); each dot-separated\n/// segment must be non-empty and not start with a digit. We don't\n/// enforce the segment-leading-letter rule strictly (some legacy apps\n/// use digits) but we do reject empty segments and obvious shell\n/// metacharacters — the identifier ends up as a `codesign` argument and\n/// a path component of the helper bundles.\nfn validate_bundle_identifier(id: &str) -> Result<(), AnyError> {\n  if id.is_empty() {\n    bail!(\"bundle identifier is empty\");\n  }\n  if id.len() > 155 {\n    // Apple's documented limit for CFBundleIdentifier on receipts is\n    // 155 chars; bigger values quietly truncate elsewhere in the\n    // toolchain.\n    bail!(\"bundle identifier {id:?} is longer than 155 characters\");\n  }\n  if !id.contains('.') {\n    bail!(\n      \"bundle identifier {id:?} must be in reverse-DNS form (e.g. com.acme.foo)\"\n    );\n  }\n  for c in id.chars() {\n    if !(c.is_ascii_alphanumeric() || c == '.' || c == '-') {\n      bail!(\n        \"bundle identifier {id:?} must match [A-Za-z0-9.-]+, but contains {c:?}\",\n      );\n    }","sourceCodeStart":2445,"sourceCodeEnd":2481,"githubUrl":"https://github.com/denoland/deno/blob/f7822238cab635a3a19f99f493f675fa81a7f9d8/cli/tools/desktop.rs#L2445-L2481","documentation":"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.","triggerScenarios":"`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.","commonSituations":"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.","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>`."],"exampleFix":"# before\ndeno desktop --identifier \"$BUNDLE_ID\" main.ts   # BUNDLE_ID unset -> \"\"\n\n# after\nexport BUNDLE_ID=com.acme.myapp\ndeno desktop --identifier \"$BUNDLE_ID\" main.ts","handlingStrategy":"validation","validationCode":"# bash: refuse to pass an empty identifier\n[[ -n \"${BUNDLE_ID:-}\" ]] || { echo \"BUNDLE_ID is empty\" >&2; exit 1; }\ndeno desktop --identifier \"$BUNDLE_ID\" main.ts","typeGuard":"// TypeScript\nfunction isNonEmptyBundleIdentifier(id: string | undefined): id is string {\n  return typeof id === \"string\" && id.length > 0;\n}","tryCatchPattern":null,"preventionTips":["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."],"tags":["desktop","bundle-identifier","validation","cli"],"backgroundTag":"invalid-bundle-identifier","analyzedSha":"f7822238cab635a3a19f99f493f675fa81a7f9d8","analyzedAt":"2026-08-20T13:07:44.778Z","contentChangedAt":"2026-08-20T13:07:44.778Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}