{"record":{"id":"513c518ce3bb07f6","repo":"denoland/deno","slug":"cannot-build-a-msi-from-an-empty-app-directory","errorCode":null,"errorMessage":"Cannot build a .msi from an empty app directory","messagePattern":"Cannot build a \\.msi from an empty app directory","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cli/tools/desktop.rs","lineNumber":4746,"sourceCode":"    let long = rel\n      .file_name()\n      .map(|s| s.to_string_lossy().into_owned())\n      .unwrap_or_else(|| key.clone());\n    short_counter += 1;\n    files.push(MsiFile {\n      key,\n      component,\n      file_name: format!(\n        \"{}|{}\",\n        msi_short_name(short_counter, &long, false),\n        long\n      ),\n      size: *size,\n      abs_path: app_dir.join(rel),\n    });\n  }\n  if files.is_empty() {\n    bail!(\"Cannot build a .msi from an empty app directory\");\n  }\n\n  // Locate the laufey launcher in the install root so we can author a Start Menu\n  // shortcut to it (otherwise the installed app is not discoverable — there is no\n  // icon anywhere, only files under Program Files). The launcher is the backend\n  // binary renamed to `<app>.exe`; it auto-loads the co-located `<app>.dll`\n  // runtime, so the shortcut targets it directly with no arguments.\n  let launcher_exe = format!(\"{app_name}.exe\").to_ascii_lowercase();\n  let shortcut_target = rel_files\n    .iter()\n    .zip(files.iter())\n    .find(|((rel, _), _)| {\n      rel.parent() == Some(Path::new(\"\"))\n        && rel\n          .file_name()\n          .and_then(|n| n.to_str())\n          .is_some_and(|n| n.to_ascii_lowercase() == launcher_exe)\n    })","sourceCodeStart":4728,"sourceCodeEnd":4764,"githubUrl":"https://github.com/denoland/deno/blob/f7822238cab635a3a19f99f493f675fa81a7f9d8/cli/tools/desktop.rs#L4728-L4764","documentation":"The MSI builder walks the staged app directory and collects every file into install components; an MSI with zero files is meaningless, so the build bails when the walk produced nothing. It means the directory the bundler was pointed at is empty — usually the preceding compile/bundle step failed to place output, or the path is wrong.","triggerScenarios":"`deno desktop` packaging a .msi where the app directory contains no files: an earlier build stage failed silently, the output/staging path is misconfigured, or a cleanup step emptied it between stages.","commonSituations":"CI pipelines where the compile step and packaging step are separate jobs and artifacts didn't transfer; wrong --output path pointing at a freshly-created empty dir.","solutions":["Verify the app directory actually contains your compiled output (list its files) before the MSI step.","Re-run the preceding build/compile step and confirm it succeeded before packaging.","Check the --output / staging path configuration for typos or wrong job-workspace paths in CI."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"# Fail the pipeline before the MSI step if the staged app dir is empty\n[ -n \"$(find \"$APP_DIR\" -type f -print -quit)\" ] || {\n  echo \"app dir '$APP_DIR' is empty — compile step produced nothing\"; exit 1;\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Chain compile and packaging steps in one job, or verify artifacts transferred between CI jobs.","Assert non-empty output dirs after every build stage, not just before MSI."],"tags":["desktop","windows","msi","packaging","build-pipeline"],"backgroundTag":"empty-build-output","analyzedSha":"f7822238cab635a3a19f99f493f675fa81a7f9d8","analyzedAt":"2026-08-20T13:07:44.778Z","contentChangedAt":"2026-08-20T13:07:44.778Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}