denoland/deno · error

icon sets are not supported in --hmr mode yet

Error message

icon sets are not supported in --hmr mode yet

What it means

Thrown by resolve_hmr_icon_path (macOS only) when `deno desktop --hmr` is asked to show an app icon that was configured as an icon SET — a size-to-path mapping (IconConfig::Set) — rather than a single .icns/.png file. The HMR dev loop passes one icon path to the LAUFEY backend via LAUFEY_APP_ICON (`-[NSImage initWithContentsOfFile:]`), which has no concept of a size set, so sets are not supported in HMR mode yet.

Solutions

  1. Point the config at a single .icns (preferred on macOS, contains all sizes) or .png for the duration of HMR development.
  2. Or override on the CLI with a single icon: `deno desktop --hmr --icon assets/AppIcon.icns main.ts`.
  3. Or drop the icon configuration for dev runs — HMR works without an icon.

Example fix

// deno.json (or deno.jsonc) — before
{
  "desktop": {
    "icon": { "16": "icons/16.png", "32": "icons/32.png", "512": "icons/512.png" }
  }
}

// after
{
  "desktop": {
    "icon": "icons/AppIcon.icns"
  }
}
Defensive patterns

Strategy: validation

Validate before calling

# bash: fail early if hmr is combined with an icon set
if deno json 2>/dev/null | jq -e '.desktop.icon | type == "object"' >/dev/null 2>&1 && [[ "$1" == *--hmr* ]]; then
  echo "icon sets are unsupported with --hmr; use a single .icns/.png" >&2; exit 1
fi
deno desktop --hmr main.ts

Type guard

// TypeScript (config check before dev runs)
function isIconSet(cfg: { desktop?: { icon?: unknown } }): boolean {
  return typeof cfg.desktop?.icon === "object" && cfg.desktop?.icon !== null;
}
// if (wantsHmr && isIconSet(config)) -> switch config to a single icon string

Prevention

When it happens

Trigger: Running `deno desktop --hmr` on macOS while the config file defines `icon` as an object mapping sizes to files (DesktopIconValue::Set → IconConfig::Set), e.g. `"icon": { "16": "icons/16.png", "32": "icons/32.png" }`.

Common situations: A project configured for production bundling with a full icon set (multiple resolutions), then starting dev mode with --hmr on the same config; migrating a config from a template that ships icon sets; CI running --hmr smoke tests against the shipping config.

Related errors


AI-assisted analysis of denoland/deno@f7822238ca (2026-08-20). Data as JSON: /api/errors/35e9815ca8df9796. Report an issue: GitHub.

Appendix: source

Thrown at cli/tools/desktop.rs:1165

    format!("{}{}", bytes, UNITS[unit])
  } else {
    format!("{:.1}{}", size, UNITS[unit])
  }
}

/// Resolve `icon` (a `.png` or `.icns` path, possibly relative to
/// `initial_cwd`) into an absolute path suitable for `LAUFEY_APP_ICON`, which
/// laufey passes to `-[NSImage initWithContentsOfFile:]` (both formats are
/// accepted, so no conversion is needed).
#[cfg(target_os = "macos")]
fn resolve_hmr_icon_path(
  icon: &crate::args::IconConfig,
  initial_cwd: &Path,
) -> Result<PathBuf, AnyError> {
  let icon_path = match icon {
    crate::args::IconConfig::Single(p) => initial_cwd.join(p),
    crate::args::IconConfig::Set(_) => {
      deno_core::anyhow::bail!("icon sets are not supported in --hmr mode yet")
    }
  };
  if !icon_path.exists() {
    deno_core::anyhow::bail!("icon '{}' not found", icon_path.display());
  }
  match icon_path.extension().and_then(|e| e.to_str()) {
    Some("icns") | Some("png") => {}
    _ => deno_core::anyhow::bail!(
      "icon '{}' must be .icns or .png",
      icon_path.display()
    ),
  }
  Ok(crate::util::fs::canonicalize_path(&icon_path).unwrap_or(icon_path))
}

/// Extract the local URL from a line of dev server output.
fn parse_dev_server_url(line: &str) -> Option<String> {
  let line = console_static_text::ansi::strip_ansi_codes(line);

View on GitHub (pinned to f7822238ca)