{"record":{"id":"23a9313f19528178","repo":"denoland/deno","slug":"bundle-identifier-id-must-match-a-za-z0-9","errorCode":null,"errorMessage":"bundle identifier {id:?} must match [A-Za-z0-9.-]+, but contains {c:?}","messagePattern":"bundle identifier (.+?) must match \\[A-Za-z0-9\\.-\\]\\+, but contains (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cli/tools/desktop.rs","lineNumber":2478,"sourceCode":"/// 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`.\n///\n/// CEF's process model: when the browser process spawns a helper for a\n/// child role (gpu, renderer, plugin, …), the helper inspects its own\n/// `CFBundleIdentifier` and refuses to attach to a parent whose id\n/// doesn't match it as a prefix. laufey's default helper plists ship with\n/// `com.example.laufey.helper.*` — which is inconsistent with whatever id","sourceCodeStart":2460,"sourceCodeEnd":2496,"githubUrl":"https://github.com/denoland/deno/blob/f7822238cab635a3a19f99f493f675fa81a7f9d8/cli/tools/desktop.rs#L2460-L2496","documentation":"Thrown by validate_bundle_identifier when `--identifier` contains a character outside [A-Za-z0-9.-]; the message names the offending character. Beyond Apple's CFBundleIdentifier charset this also blocks shell metacharacters, because the identifier is passed as a `codesign` argument and used as a path component of the CEF helper bundles.","triggerScenarios":"`--identifier com.acme.my_app` (underscore — the single most common hit), spaces, `://`, quotes, unicode letters (é, ü), or any shell metacharacter in the value.","commonSituations":"Underscores carried over from npm package names or repo names; copy-pasting a URL (`https://acme.com`) instead of the reverse-DNS form; non-ASCII company/product names pasted verbatim.","solutions":["Replace invalid characters: use hyphens instead of underscores (`my-app` not `my_app`) and drop everything that is not a letter, digit, dot, or hyphen.","Transliterate non-ASCII names to plain ASCII (Bäcker -> baeker).","Use the reverse-DNS form of a domain you control rather than pasting a URL."],"exampleFix":"# before\ndeno desktop --identifier com.acme.my_app main.ts\n\n# after\ndeno desktop --identifier com.acme.my-app main.ts","handlingStrategy":"validation","validationCode":"# bash: enforce the charset\nBUNDLE_ID=\"com.acme.my-app\"\n[[ \"$BUNDLE_ID\" =~ ^[A-Za-z0-9.-]+$ ]] || { echo \"identifier has invalid characters\" >&2; exit 1; }\ndeno desktop --identifier \"$BUNDLE_ID\" main.ts","typeGuard":"// TypeScript\nfunction hasOnlyBundleIdChars(id: string): boolean {\n  return /^[A-Za-z0-9.-]+$/.test(id);\n}","tryCatchPattern":null,"preventionTips":["Use hyphens where you would use underscores (my-app, not my_app).","Transliterate non-ASCII product names to ASCII before building the id.","Add a regex lint for the identifier in CI to catch regressions early."],"tags":["desktop","bundle-identifier","validation","charset","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"}