{"record":{"id":"545110a12526d00c","repo":"AykutSarac/jsoncrack.com","slug":"failed-to-download-image","errorCode":null,"errorMessage":"Failed to download image!","messagePattern":"Failed to download image!","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"apps/www/src/features/modals/DownloadModal/index.tsx","lineNumber":138,"sourceCode":"      toast.loading(\"Downloading...\", { id: \"toastDownload\" });\n\n      const imageElement = getExportElement();\n      if (!imageElement) {\n        toast.error(\"Canvas not found.\");\n        return;\n      }\n      const imageOptions = {\n        quality: fileDetails.quality,\n        backgroundColor: fileDetails.backgroundColor,\n        skipFonts: true,\n      };\n\n      const dataURI = await getDownloadFormat(extension)(imageElement, imageOptions);\n\n      downloadURI(dataURI, `${fileDetails.filename}.${extension}`);\n      gaEvent(\"download_img\", { label: extension });\n    } catch {\n      toast.error(\"Failed to download image!\");\n    } finally {\n      toast.dismiss(\"toastDownload\");\n      onClose();\n    }\n  };\n\n  const updateDetails = (key: keyof typeof fileDetails, value: string | number) =>\n    setFileDetails({ ...fileDetails, [key]: value });\n\n  return (\n    <Modal opened={opened} onClose={onClose} title=\"Download Image\" centered>\n      <TextInput\n        label=\"File Name\"\n        value={fileDetails.filename}\n        onChange={e => updateDetails(\"filename\", e.target.value)}\n        mb=\"lg\"\n      />\n      <SegmentedControl","sourceCodeStart":120,"sourceCodeEnd":156,"githubUrl":"https://github.com/AykutSarac/jsoncrack.com/blob/3c9af69e23c635356293b6b28cf4cd0af10d1059/apps/www/src/features/modals/DownloadModal/index.tsx#L120-L156","documentation":"Generic toast from exportAsImage()'s catch when html-to-image (toSvg/toPng/toJpeg) throws. Covers rendering failures: the target node contains cross-origin images/canvas that taint the output (SecurityError), a font/image fails to load, the element is too large causing memory/timeouts, or getDownloadFormat returns undefined for an unknown extension.","triggerScenarios":"A graph referencing cross-origin images without CORS; a very large canvas triggering OOM; skipFonts is true but foreignObject still hits a tainted canvas; an extension value outside the SVG/PNG/JPEG enum making getDownloadFormat return undefined (then calling undefined() throws TypeError).","commonSituations":"Exporting large graphs; embedded remote images without CORS headers; Safari foreignObject quirks; runtime extension value drift.","solutions":["Ensure all images/fonts rendered in the canvas are same-origin or CORS-enabled.","Keep skipFonts:true (already set) to reduce font-load failures.","Validate the selected extension is one of SVG/PNG/JPEG before calling getDownloadFormat.","Log the caught error to identify the exact html-to-image failure (currently swallowed)."],"exampleFix":"// before\nconst dataURI = await getDownloadFormat(extension)(imageElement, imageOptions);\n// ...\n} catch {\n  toast.error(\"Failed to download image!\");\n}\n\n// after — guard the format lookup and log the real cause\nconst renderer = getDownloadFormat(extension);\nif (!renderer) { toast.error(\"Unknown format.\"); return; }\ntry {\n  const dataURI = await renderer(imageElement, imageOptions);\n  downloadURI(dataURI, `${fileDetails.filename}.${extension}`);\n} catch (err) {\n  console.error(err);\n  toast.error(\"Failed to download image!\");\n}","handlingStrategy":"try-catch","validationCode":"// Validate the extension maps to a renderer and content is CORS-safe\nconst KNOWN = new Set([\"svg\", \"png\", \"jpeg\"]);\nexport function canExport(ext: string): boolean {\n  return KNOWN.has(ext);\n}","typeGuard":"// Guard getDownloadFormat's return\nfunction hasRenderer(fn: unknown): fn is (el: HTMLElement, opts: unknown) => Promise<string> {\n  return typeof fn === \"function\";\n}","tryCatchPattern":"// Guard format lookup, log the html-to-image cause\nconst renderer = getDownloadFormat(extension);\nif (!hasRenderer(renderer)) { toast.error(\"Unknown format.\"); return; }\ntry { await renderer(el, opts); } catch (err) { console.error(err); toast.error(\"Failed to download image!\"); }","preventionTips":["Ensure canvas images are same-origin or CORS-enabled to avoid taint.","Keep skipFonts:true to reduce font-load failures.","Validate the extension is SVG/PNG/JPEG before calling the renderer."],"tags":["export","html-to-image","cors","download","canvas"],"backgroundTag":null,"analyzedSha":"3c9af69e23c635356293b6b28cf4cd0af10d1059","analyzedAt":"2026-08-12T19:00:27.891Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}