denoland/deno · error

no .desktop file found in

Error message

no .desktop file found in {}

What it means

While registering deep links for a compiled desktop app on Linux, Deno scans the app bundle for a `.desktop` entry file to add `x-scheme-handler/<scheme>` MIME types and an `Exec=... %u` field code. If no `*.desktop` file exists in the bundle directory, registration aborts with this error.

Solutions

  1. Rebuild the desktop bundle with the current deno version so the `.desktop` entry is generated
  2. If you customize packaging, ensure a valid `<App>.desktop` file lands in the bundle root before deep-link registration
  3. List the bundle directory — the `.desktop` file should sit alongside the executable
Defensive patterns

Strategy: validation

Validate before calling

// Pre-check the bundle before registering deep links
const bundleDir = "./dist/myapp";
const hasDesktopEntry = [...Deno.readDirSync(bundleDir)].some((e) =>
  e.name.endsWith(".desktop")
);
if (!hasDesktopEntry) {
  throw new Error("bundle has no .desktop file — rebuild before registering schemes");
}

Prevention

When it happens

Trigger: Deep-link registration (schemes declared in the desktop configuration) run against a bundle directory that contains no `.desktop` file — the bundle was built without the desktop packaging step, or the directory was assembled or modified by hand.

Common situations: Older or custom-built bundles; artifacts copied piecemeal out of the build output; packaging steps that renamed or deleted the `.desktop` file before registration.

Related errors


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

Appendix: source

Thrown at cli/tools/desktop.rs:821

    plist::Value::Array(vec![plist::Value::Dictionary(url_type)]),
  );

  plist::to_file_xml(&plist_path, &dict)
    .with_context(|| format!("failed to write {}", plist_path.display()))?;
  Ok(())
}

/// Linux: add `x-scheme-handler/<scheme>` MIME types to the `.desktop` entry
/// and make sure `Exec=` forwards the opened URL via the `%u` field code.
fn register_deep_links_linux(
  bundle_path: &Path,
  schemes: &[String],
) -> Result<(), AnyError> {
  let desktop_file = std::fs::read_dir(bundle_path)?
    .filter_map(|e| e.ok().map(|e| e.path()))
    .find(|p| p.extension().is_some_and(|e| e == "desktop"))
    .ok_or_else(|| {
      deno_core::anyhow::anyhow!(
        "no .desktop file found in {}",
        bundle_path.display()
      )
    })?;

  let contents = std::fs::read_to_string(&desktop_file)?;
  let mime = schemes
    .iter()
    .map(|s| format!("x-scheme-handler/{s};"))
    .collect::<String>();

  let mut out = String::with_capacity(contents.len() + mime.len() + 16);
  let mut wrote_mime = false;
  for line in contents.lines() {
    if let Some(rest) = line.strip_prefix("Exec=") {
      // The launcher must receive the URL as an argument, so ensure a `%u`
      // field code is present exactly once.
      if rest.contains("%u") || rest.contains("%U") {

View on GitHub (pinned to f7822238ca)