AykutSarac/jsoncrack.com · error

Failed to copy to clipboard

Error message

Failed to copy to clipboard

What it means

Generic clipboard failure toast from clipboardImage()'s catch — the branch taken when the error is NOT a NotAllowedError. Covers any other DOMException or thrown error from the clipboard pipeline: unsupported MIME type in ClipboardItem (e.g. image/svg+xml is not universally supported), AbortError, SecurityError, or NotSupportedError.

Source

Thrown at apps/www/src/features/modals/DownloadModal/index.tsx:110

      const blob = await toBlob(imageElement, imageOptions);

      if (!blob) return;

      await navigator.clipboard?.write([
        new ClipboardItem({
          [blob.type]: blob,
        }),
      ]);

      toast.success("Copied to clipboard");
      gaEvent("clipboard_img");
    } catch (error) {
      if (error instanceof Error && error.name === "NotAllowedError") {
        toast.error(
          "Clipboard write permission denied. Please allow clipboard access in your browser settings."
        );
      } else {
        toast.error("Failed to copy to clipboard");
      }
    } finally {
      toast.dismiss("toastClipboard");
      onClose();
    }
  };

  const exportAsImage = async () => {
    try {
      toast.loading("Downloading...", { id: "toastDownload" });

      const imageElement = getExportElement();
      if (!imageElement) {
        toast.error("Canvas not found.");
        return;
      }
      const imageOptions = {
        quality: fileDetails.quality,

View on GitHub (pinned to 3c9af69e23)

Solutions

  1. Force PNG for the clipboard path (render a PNG blob) regardless of the selected extension.
  2. Check typeof ClipboardItem and blob.type support before calling write.
  3. Log the actual error to distinguish NotSupportedError from AbortError.
  4. Offer a download fallback when clipboard write is unsupported.

Example fix

// before
const blob = await toBlob(imageElement, imageOptions);
if (!blob) return;
await navigator.clipboard?.write([new ClipboardItem({ [blob.type]: blob })]);

// after — always use PNG for clipboard compatibility
const pngBlob = await toPng(imageElement, imageOptions);
if (!pngBlob) return;
const type = ClipboardItem.supports("image/png") ? "image/png" : pngBlob.type;
await navigator.clipboard?.write([new ClipboardItem({ [type]: pngBlob })]);
Defensive patterns

Strategy: validation

Validate before calling

// Force a clipboard-safe MIME type
export function clipboardSupportedType(blob: Blob): string {
  return typeof ClipboardItem !== "undefined" && ClipboardItem.supports?.("image/png")
    ? "image/png"
    : blob.type;
}

Type guard

// Detect unsupported clipboard image types
export function isUnsupportedClipboard(error: unknown): boolean {
  return error instanceof DOMException && (error.name === "NotSupportedError" || error.name === "AbortError");
}

Try / catch

// Distinguish unsupported-type from other failures
try {
  await navigator.clipboard?.write([new ClipboardItem({ [type]: blob })]);
} catch (error) {
  if (isUnsupportedClipboard(error)) downloadURI(URL.createObjectURL(blob), name);
  else toast.error("Failed to copy to clipboard");
}

Prevention

When it happens

Trigger: Trying to copy an SVG blob via navigator.clipboard.write (many browsers only accept image/png in ClipboardItem); a null blob (the `if (!blob) return` guard exists but a later await may still fail); the browser does not implement ClipboardItem for the given type.

Common situations: Exporting as SVG then clicking Clipboard (SVG MIME unsupported by async clipboard API); Firefox/Safari limitations on clipboard image types; transient AbortError from rapid repeated clicks.

Related errors


AI-assisted analysis of AykutSarac/jsoncrack.com@3c9af69e23 (2026-08-12). Data as JSON: /api/errors/1773125f0b284a1b. Report an issue: GitHub.