schollz/croc · info · DOMException

AbortError

AbortError

Error message

Destination selection cancelled

What it means

Thrown as a DOMException with name AbortError by chooseReceiveDestination after the user was shown a window.confirm overwrite dialog for existing files in the picked directory and declined to replace them. It signals deliberate user cancellation of destination selection, not a system failure. Existing-file detection is done per offer file via fileExists() against the picked directory handle.

Source

Thrown at web/src/protocol/storage.ts:362

      window.location.hostname === "localhost" ||
      window.location.hostname === "127.0.0.1")
  );
}

export async function chooseReceiveDestination(offer: TransferOffer) {
  if (!window.showDirectoryPicker) return new DownloadDestination();
  const directory = await window.showDirectoryPicker({ mode: "readwrite" });
  const collisions: string[] = [];
  for (const file of offer.files) {
    if (await fileExists(directory, file)) collisions.push(file.path);
  }
  if (
    collisions.length > 0 &&
    !window.confirm(
      `${collisions.length} file${collisions.length === 1 ? "" : "s"} already exist in that folder. Replace them?`,
    )
  ) {
    throw new DOMException("Destination selection cancelled", "AbortError");
  }
  return new DirectoryDestination(directory);
}

export async function chooseStoredReceiveDestination(offer: TransferOffer) {
  if (window.showDirectoryPicker) {
    return chooseReceiveDestination(offer);
  }
  if (supportsStreamingDownloadDestination()) {
    return new StreamingDownloadDestination();
  }
  const largest = offer.files.reduce(
    (maximum, file) => Math.max(maximum, file.size),
    0,
  );
  if (largest > 256 * 1024 * 1024) {
    throw new Error(
      "This browser cannot stream a file this large. Receive it with the croc CLI instead.",

View on GitHub (pinned to e25f1bdc04)

Solutions

  1. Catch DOMException with name === "AbortError" around chooseReceiveDestination/chooseStoredReceiveDestination and treat it as a benign user cancel (stop quietly or re-prompt)
  2. If the user should proceed, instruct them to confirm the replace dialog or pick a different/empty folder
  3. Pre-clean or rename colliding files in the target folder before re-running the receive

Example fix

// before
const destination = await chooseReceiveDestination(offer);

// after
try {
  const destination = await chooseReceiveDestination(offer);
} catch (error) {
  if (error instanceof DOMException && error.name === "AbortError") return; // user cancelled
  throw error;
}
Defensive patterns

Strategy: try-catch

Type guard

const isUserCancel = (e: unknown): boolean => e instanceof DOMException && e.name === "AbortError";

Try / catch

try { destination = await chooseStoredReceiveDestination(offer); } catch (e) { if (e instanceof DOMException && e.name === "AbortError") { showCancelledState(); return; } throw e; }

Prevention

When it happens

Trigger: window.showDirectoryPicker({mode:"readwrite"}) succeeds, one or more offered file paths already exist in the chosen folder, and the user clicks Cancel on the "N file(s) already exist in that folder. Replace them?" confirm dialog.

Common situations: Re-running a receive into the same folder after a partial earlier transfer; receivers who deliberately do not want to clobber existing data. Note the directory picker's own Cancel produces a different AbortError from showDirectoryPicker itself, so catch code must handle both origins gracefully.

Related errors


AI-assisted analysis of schollz/croc@e25f1bdc04 (2026-08-15). Data as JSON: /api/errors/e1a2f93af30c4093. Report an issue: GitHub.