denoland/deno · error

No valid icon images found for .icns

Error message

No valid icon images found for .icns

What it means

The .icns builder iterates configured icon entries: files that don't exist are skipped with a warning, and sizes that don't map to a standard macOS iconset slot (only 16/32/64/128/256/512/1024 are recognized by icns_ostypes_for_size) contribute no OSType and are also skipped with a warning. If no entry survives — none of the files exist, or all sizes are non-standard — the build bails.

Solutions

  1. Fix the icon paths so each resolves relative to the cwd you run `deno desktop` from.
  2. Use only standard iconset sizes: 16, 32, 64, 128, 256, 512, 1024.
  3. Watch the preceding 'Icon ... not found, skipping' and "doesn't map to a standard macOS iconset slot" warnings — they say exactly which entries dropped out.
  4. Make sure at least one icon file is committed/exists on the build machine.

Example fix

// before: wrong relative root + non-standard size
"icons": [{ "path": "./assets/icons/logo_48.png", "size": 48 }]

// after
"icons": [{ "path": "assets/icons/logo_256.png", "size": 256 }]
Defensive patterns

Strategy: validation

Validate before calling

// Validate icon config before building (paths are cwd-relative; sizes must be iconset slots)
const ICONSET_SIZES = new Set([16, 32, 64, 128, 256, 512, 1024]);
for (const icon of config.desktop.icons) {
  if (!ICONSET_SIZES.has(icon.size)) throw new Error(`size ${icon.size} is not a standard iconset slot`);
  if (!existsSync(icon.path)) throw new Error(`icon not found: ${icon.path}`);
}

Type guard

function isStandardIconsetSize(n: number): boolean {
  return [16, 32, 64, 128, 256, 512, 1024].includes(n);
}

Prevention

When it happens

Trigger: All icon paths in the desktop config resolve to nonexistent files (paths are joined against the project cwd, so wrong relative paths are the usual cause), or every configured size is unsupported (48, 0, 999...), so icons ends up empty even though files exist.

Common situations: Icons declared relative to the config file instead of the working directory; sizes like 48 or 20 picked by hand; icon files excluded from git so only CI fails.

Related errors


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

Appendix: source

Thrown at cli/tools/desktop.rs:5536

  icns_path: &Path,
) -> Result<(), deno_core::error::AnyError> {
  use std::io::Write;

  let mut icons: Vec<(&'static [u8; 4], Vec<u8>)> = Vec::new();
  for entry in entries {
    let src = cwd.join(&entry.path);
    if !src.exists() {
      log::warn!("Icon '{}' not found, skipping", src.display());
      continue;
    }
    let data = std::fs::read(&src)?;
    for code in icns_ostypes_for_size(entry.size) {
      icons.push((*code, data.clone()));
    }
  }

  if icons.is_empty() {
    deno_core::anyhow::bail!("No valid icon images found for .icns");
  }

  // File header (8 bytes) + for each icon: 4-byte OSType + 4-byte length + payload.
  let total_size: u32 = icons
    .iter()
    .map(|(_, data)| 8 + data.len() as u32)
    .sum::<u32>()
    + 8;

  let mut buf = Vec::with_capacity(total_size as usize);
  buf.write_all(b"icns")?;
  buf.write_all(&total_size.to_be_bytes())?;
  for (code, data) in &icons {
    buf.write_all(*code)?;
    let entry_len = 8 + data.len() as u32;
    buf.write_all(&entry_len.to_be_bytes())?;
    buf.write_all(data)?;
  }

View on GitHub (pinned to f7822238ca)