different-ai/openwork · error

destination-exists

destination-exists

Error message

Download destination already exists.

What it means

downloadBinaryToPath creates the destination exclusively with open(path, "wx"), which never follows a final symlink; an EEXIST is converted to the coded error 'destination-exists'. This prevents silently overwriting user files and blocks symlink attacks on the destination path. The destination must also resolve inside the authorized roots before this check.

Solutions

  1. Delete or rename the existing file first (fs.rm / rename) if overwriting is intended.
  2. Pick a unique destinationPath (timestamp/UUID suffix or version in the filename).
  3. Add an existence check before the call and branch: skip, resume, or overwrite explicitly.
  4. Serialize concurrent workers so only one downloads to a given path.

Example fix

// before
await downloadBinaryToPath({ url, destinationPath });
// after
import { rm } from "node:fs/promises";
await rm(destinationPath, { force: true }); // explicit overwrite intent
await downloadBinaryToPath({ url, destinationPath });
Defensive patterns

Strategy: validation

Validate before calling

import { lstat } from "node:fs/promises";
let exists = false;
try { await lstat(destinationPath); exists = true; } catch (e) { if (e.code !== "ENOENT") throw e; }
if (exists) throw new Error(`Choose another destination; ${destinationPath} already exists`);

Type guard

async function isFreeDestination(p) {
  try { await lstat(p); return false; } catch (e) { return e.code === "ENOENT"; }
}

Try / catch

try {
  await downloadBinaryToPath({ url, destinationPath });
} catch (e) {
  if (e?.code === "destination-exists") {
    return { ok: false, reason: "exists", path: destinationPath };
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling downloadBinaryToPath with destinationPath pointing at a path that already exists (file, or dangling/symlinked entry) — open("wx") raises EEXIST which is remapped to this error.

Common situations: Re-running a setup script that already downloaded the file; two concurrent workers downloading to the same path; stale artifact from a previous version; a symlink planted at the destination path.

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 different-ai/openwork@2b7df46e8a (2026-09-01). Data as JSON: /api/errors/7ada1f1eeedb40e5. Report an issue: GitHub.

Appendix: source

Thrown at apps/desktop/electron/binary-transfer.mjs:322

        bytes += value.byteLength;
        if (bytes > maxBytes) {
          await reader.cancel();
          throw transferError(`Download exceeds the ${maxBytes}-byte limit.`, "file-too-large");
        }
        await writeAll(stagingFile, value);
      }
    }
    if (bytes === 0) throw transferError("Download response was empty.", "zero-byte-file");
    // Only a complete download reaches the workspace. Revalidate the
    // destination, create it exclusively ("wx" never follows a final
    // symlink), and prove by device and inode that the created file resides
    // inside the authorized root before a single byte is written to it.
    await resolveAuthorizedPath(input?.destinationPath, options?.authorizedRoots);
    try {
      destinationFile = await open(destinationPath, "wx");
    } catch (error) {
      if (error?.code === "EEXIST") {
        throw transferError("Download destination already exists.", "destination-exists");
      }
      throw error;
    }
    await verifyOpenFileWithinRoot(destinationFile, destinationPath, destination.rootRealPath, "Download destination");
    const buffer = Buffer.allocUnsafe(1024 * 1024);
    let position = 0;
    while (position < bytes) {
      signal?.throwIfAborted();
      const { bytesRead } = await stagingFile.read(buffer, 0, Math.min(buffer.length, bytes - position), position);
      if (bytesRead === 0) {
        throw transferError("Downloaded data changed while it was being saved.", "size-mismatch");
      }
      await writeAll(destinationFile, buffer.subarray(0, bytesRead));
      position += bytesRead;
    }
    await destinationFile.sync();
    await destinationFile.close();
    destinationFile = undefined;

View on GitHub (pinned to 2b7df46e8a)