{"record":{"id":"be98e428f9934e29","repo":"denoland/deno","slug":"bundle-identifier-id-must-be-in-reverse-dns-fo","errorCode":null,"errorMessage":"bundle identifier {id:?} must be in reverse-DNS form (e.g. com.acme.foo)","messagePattern":"bundle identifier (.+?) must be in reverse-DNS form \\(e\\.g\\. com\\.acme\\.foo\\)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cli/tools/desktop.rs","lineNumber":2472,"sourceCode":"/// 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    }\n  }\n  if id.split('.').any(|seg| seg.is_empty()) {\n    bail!(\"bundle identifier {id:?} has an empty segment\");\n  }\n  Ok(())\n}\n\n/// Walk every `.app` under `Contents/Frameworks/` and rewrite its\n/// `CFBundleIdentifier` so it's a strict suffix of `main_bundle_id`.","sourceCodeStart":2454,"sourceCodeEnd":2490,"githubUrl":"https://github.com/denoland/deno/blob/f7822238cab635a3a19f99f493f675fa81a7f9d8/cli/tools/desktop.rs#L2454-L2490","documentation":"Thrown by validate_bundle_identifier when `--identifier` contains no dot. Apple expects a reverse-DNS form (at least one dot, like com.acme.foo); the identifier is also used for Linux .desktop filenames and Windows AppUserModelID, where the dotted form is the convention. A single bare word like `myapp` fails this check.","triggerScenarios":"`deno desktop --identifier myapp main.ts`; `--identifier MyApp`; identifiers written in Java-package style without dots after a rename; a value like `acme:` where the dot was lost to shell quoting.","commonSituations":"Devs used to Electron's `name` field or Android `appId` without dots passing a bare word; config migration where `com.acme.myapp` got truncated to its last segment; quoting typos splitting the string.","solutions":["Use full reverse-DNS: `com.acme.myapp` (at least one dot required).","If you have no company domain, a stable placeholder like `com.example.<appname>` or `io.github.<user>.<app>` works.","Or omit `--identifier` entirely to use the synthesized `com.deno.desktop.<slug>`."],"exampleFix":"# before\ndeno desktop --identifier myapp main.ts\n\n# after\ndeno desktop --identifier com.acme.myapp main.ts","handlingStrategy":"validation","validationCode":"# bash: require reverse-DNS form\nBUNDLE_ID=\"com.acme.myapp\"\n[[ \"$BUNDLE_ID\" == *.* ]] || { echo \"identifier must contain a dot\" >&2; exit 1; }\ndeno desktop --identifier \"$BUNDLE_ID\" main.ts","typeGuard":"// TypeScript\nfunction isReverseDnsLike(id: string): boolean {\n  return id.includes(\".\");\n}","tryCatchPattern":null,"preventionTips":["Derive the identifier from a domain you control (com.acme.myapp).","Or leave --identifier off and accept the synthesized com.deno.desktop.<slug>.","Do not paste URLs or bare product names as the identifier."],"tags":["desktop","bundle-identifier","validation","reverse-dns","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-14T05:17:10.506Z"}