Hmbown/CodeWhale · error · Error

The installation destination contains a different…

Error message

The installation destination contains a different application.

What it means

replaceMacBundle refuses to overwrite an existing destination bundle unless it looks like this app's bundle (it must contain Contents/Resources/plugin/app/daemon.mjs). This guards against clobbering an unrelated .app the user placed at the same path, which would destroy another application's data.

Solutions

  1. Remove or move the unrelated item at destination, or point destination at a free path
  2. Verify the destination is the correct install location and contains the expected daemon.mjs marker if it should be this app
  3. If it is a stale install of this app, reinstall cleanly from scratch rather than replacing
  4. Confirm bundle layout matches the current app structure (Contents/Resources/plugin/app/daemon.mjs)

Example fix

// before
code.replaceMacBundle(stagedBundle, "/Applications/SomeOther.app");
// after
code.replaceMacBundle(stagedBundle, "/Applications/Codewhale Computer Use.app");
Defensive patterns

Strategy: validation

Validate before calling

const marker = path.join(destination, "Contents", "Resources", "plugin", "app", "daemon.mjs");
if (fs.existsSync(destination) && !fs.existsSync(marker)) {
  throw new Error("destination holds a different app");
}

Try / catch

try {
  replaceMacBundle(src, dest);
} catch (e) {
  if (e.message.includes("different application")) {
    promptUser(`Move the existing app at ${dest} before installing.`);
  } else throw e;
}

Prevention

When it happens

Trigger: Calling replaceMacBundle(source, destination) where destination exists but lacks the daemon.mjs marker file — i.e. a different .app bundle, a plain directory, or a bundle from a differently-structured app sits at the install path.

Common situations: Install destination changed to a path that already hosts another app (e.g. a name collision under /Applications); an old install layout predating the plugin/app directory structure; a partially deleted bundle missing its resources.

Understand the failure class

Background: "already exists" / EEXIST / FileAlreadyExistsException: what the 'file already exists' error means and how to fix it — this error's family across 37 libraries.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22). Data as JSON: /api/errors/85bccb767f8f155f. Report an issue: GitHub.

Appendix: source

Thrown at crates/tui/plugins/computer-use/app/install-macos.mjs:10

import fs from "node:fs";
import path from "node:path";
import crypto from "node:crypto";
import { spawnSync } from "node:child_process";

/** Publish a verified bundle in one rename, retaining the previous install. */
export function replaceMacBundle(source, destination, { prepare = () => {}, verify = verifySignature } = {}) {
  const parent = path.dirname(destination);
  fs.mkdirSync(parent, { recursive: true });
  if (fs.existsSync(destination) && !fs.existsSync(path.join(destination, "Contents", "Resources", "plugin", "app", "daemon.mjs"))) throw new Error("The installation destination contains a different application.");
  if (fs.existsSync(destination) && fs.lstatSync(destination).isSymbolicLink()) throw new Error("The installation destination must not be a symlink.");
  const staging = fs.mkdtempSync(path.join(parent, ".codewhale-cu-update-"));
  const next = path.join(staging, path.basename(destination));
  let backup = null;
  try {
    fs.cpSync(source, next, { recursive: true });
    prepare(next);
    verify(next);
    if (fs.existsSync(destination)) {
      const backups = path.join(parent, ".codewhale-cu-backups");
      fs.mkdirSync(backups, { recursive: true, mode: 0o700 });
      backup = path.join(backups, `${Date.now()}-${crypto.randomUUID()}.app`);
      fs.renameSync(destination, backup);
    }
    try { fs.renameSync(next, destination); }
    catch (error) { if (backup) fs.renameSync(backup, destination); throw error; }
    return { backup };
  } finally { fs.rmSync(staging, { recursive: true, force: true }); }

View on GitHub (pinned to 73e0f67d83)