{"record":{"id":"6a88fa802e9efbbf","repo":"denoland/deno","slug":"icon-must-be-icns-or-png","errorCode":null,"errorMessage":"icon '{}' must be .icns or .png","messagePattern":"icon '(.+?)' must be \\.icns or \\.png","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cli/tools/desktop.rs","lineNumber":1173,"sourceCode":"/// laufey passes to `-[NSImage initWithContentsOfFile:]` (both formats are\n/// accepted, so no conversion is needed).\n#[cfg(target_os = \"macos\")]\nfn resolve_hmr_icon_path(\n  icon: &crate::args::IconConfig,\n  initial_cwd: &Path,\n) -> Result<PathBuf, AnyError> {\n  let icon_path = match icon {\n    crate::args::IconConfig::Single(p) => initial_cwd.join(p),\n    crate::args::IconConfig::Set(_) => {\n      deno_core::anyhow::bail!(\"icon sets are not supported in --hmr mode yet\")\n    }\n  };\n  if !icon_path.exists() {\n    deno_core::anyhow::bail!(\"icon '{}' not found\", icon_path.display());\n  }\n  match icon_path.extension().and_then(|e| e.to_str()) {\n    Some(\"icns\") | Some(\"png\") => {}\n    _ => deno_core::anyhow::bail!(\n      \"icon '{}' must be .icns or .png\",\n      icon_path.display()\n    ),\n  }\n  Ok(crate::util::fs::canonicalize_path(&icon_path).unwrap_or(icon_path))\n}\n\n/// Extract the local URL from a line of dev server output.\nfn parse_dev_server_url(line: &str) -> Option<String> {\n  let line = console_static_text::ansi::strip_ansi_codes(line);\n  // Vite prints `  ➜  Local:   http://localhost:5173/`\n  regex::Regex::new(r\"Local:\\s+(https?://\\S+)\")\n    .expect(\"regex to parse local url failed\")\n    .captures(&line)\n    .and_then(|c| c.get(1))\n    .map(|m| m.as_str().to_owned())\n}\n","sourceCodeStart":1155,"sourceCodeEnd":1191,"githubUrl":"https://github.com/denoland/deno/blob/f7822238cab635a3a19f99f493f675fa81a7f9d8/cli/tools/desktop.rs#L1155-L1191","documentation":"Thrown by resolve_hmr_icon_path (macOS only) when the single icon file exists but its extension is neither .icns nor .png — the only two formats the LAUFEY backend accepts via LAUFEY_APP_ICON / `-[NSImage initWithContentsOfFile:]`. The check is on the file extension, not on decoded image content.","triggerScenarios":"`--icon assets/AppIcon.svg`, `.jpg`, `.jpeg`, `.ico`, `.webp`, or `.bmp` on macOS with `deno desktop --hmr`; a file with no extension; upper-case extensions like `.PNG` are also rejected because the match is on the exact lowercase strings \"icns\"/\"png\".","commonSituations":"Designers hand over SVG or JPG source assets; a .ico reused from a Windows build; file named `AppIcon.icns.txt` after a bad download; uppercase extension from a case-renaming script.","solutions":["Convert the image to PNG (`magick input.svg output.png`) or build a proper .icns with iconutil/Icon Composer.","If the file IS a png/icns but misnamed, rename it to the exact lowercase extension: `mv AppIcon.PNG AppIcon.png`.","Use a real conversion — merely changing the extension of a JPG/ICO does not change the file format and will fail at render time."],"exampleFix":"# before\ndeno desktop --hmr --icon assets/AppIcon.svg main.ts\n\n# after\nmagick assets/AppIcon.svg assets/AppIcon.png\ndeno desktop --hmr --icon assets/AppIcon.png main.ts","handlingStrategy":"validation","validationCode":"# bash: enforce the accepted extensions\nICON=\"$1\"\ncase \"$ICON\" in *.icns|*.png) ;; *) echo \"icon must be .icns or .png\" >&2; exit 1;; esac\ndeno desktop --hmr --icon \"$ICON\" main.ts","typeGuard":"// TypeScript\nfunction isAcceptedHmrIcon(p: string): boolean {\n  return p.endsWith(\".icns\") || p.endsWith(\".png\");\n}","tryCatchPattern":null,"preventionTips":["Convert design sources (SVG/JPG) to PNG or build an .icns in your asset pipeline.","Use lowercase extensions (.png, .icns) — the check is exact.","Remember renaming a file's extension does not convert its format."],"tags":["desktop","hmr","icon","file-format","macos","validation"],"backgroundTag":"unsupported-file-format","analyzedSha":"f7822238cab635a3a19f99f493f675fa81a7f9d8","analyzedAt":"2026-08-20T13:07:44.778Z","contentChangedAt":"2026-08-20T13:07:44.778Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}