{"record":{"id":"8df89ab441ce6312","repo":"danny-avila/LibreChat","slug":"mermaid-diagram-has-invalid-export-dimensions","errorCode":null,"errorMessage":"Mermaid diagram has invalid export dimensions","messagePattern":"Mermaid diagram has invalid export dimensions","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"client/src/utils/diagram/export.ts","lineNumber":178,"sourceCode":"      resolve(reader.result);\n    };\n    reader.onerror = () => reject(new Error('Failed to prepare Mermaid SVG for PNG export'));\n    reader.readAsDataURL(blob);\n  });\n}\n\nfunction loadSvgImage(url: string): Promise<HTMLImageElement> {\n  return new Promise((resolve, reject) => {\n    const image = new Image();\n    image.onload = () => resolve(image);\n    image.onerror = () => reject(new Error('Failed to load Mermaid SVG for PNG export'));\n    image.src = url;\n  });\n}\n\nexport function resolveCanvasDimensions(width: number, height: number): MermaidDimensions {\n  if (!Number.isFinite(width) || !Number.isFinite(height) || width <= 0 || height <= 0) {\n    throw new Error('Mermaid diagram has invalid export dimensions');\n  }\n\n  const scale = Math.min(\n    PNG_EXPORT_SCALE,\n    MAX_CANVAS_DIMENSION / width,\n    MAX_CANVAS_DIMENSION / height,\n    Math.sqrt(MAX_CANVAS_PIXELS / (width * height)),\n  );\n\n  /* Round down: rounding each side independently can carry the product back\n   * over the pixel budget the scale was chosen to satisfy, and a canvas above\n   * that area makes `toBlob` fail outright in browsers that enforce it. */\n  return {\n    width: Math.max(1, Math.floor(width * scale)),\n    height: Math.max(1, Math.floor(height * scale)),\n  };\n}\n","sourceCodeStart":160,"sourceCodeEnd":196,"githubUrl":"https://github.com/danny-avila/LibreChat/blob/5ff282f9006c436e561de1afd39a481bea1ef0d8/client/src/utils/diagram/export.ts#L160-L196","documentation":"Thrown by `resolveCanvasDimensions` when the source width or height is not a finite positive number. This guard protects the canvas pixel-budget math (scale = min of PNG_EXPORT_SCALE=2, 16384/max-dim, sqrt(16777216/area)). Non-finite/zero/negative dimensions would break the scale calculation and produce a degenerate canvas, so it fails fast. The source dimensions come from the rendered Mermaid SVG's measured `naturalWidth`/`width` or from caller-supplied `dimensions`.","triggerScenarios":"The Mermaid SVG rendered but reported zero/undefined dimensions (e.g. `display:none` container, SVG with no `viewBox`/`width`/`height`, or measured before layout settled); the caller passed a `dimensions` object with NaN/0; the SVG's width/height attributes are missing and `naturalWidth` fell back to 0.","commonSituations":"Exporting a Mermaid diagram that was rendered in a hidden/offscreen container (clientWidth/Height 0); an SVG missing width/height/viewBox; exporting before the browser has laid out the SVG; a custom diagram type Mermaid rendered as empty markup.","solutions":["Ensure the Mermaid SVG is rendered in a visible, laid-out container before export (the hook should measure after paint).","If the SVG lacks width/height, parse the `viewBox` attribute and derive dimensions from it before calling export.","Validate the measured dimensions are finite positive numbers before invoking `downloadMermaidPng`.","If the diagram genuinely has no intrinsic size, supply explicit `dimensions` from the caller."],"exampleFix":"// before\nconst sourceWidth = dimensions?.width || image.naturalWidth || image.width;\nconst sourceHeight = dimensions?.height || image.naturalHeight || image.height;\nconst canvasDimensions = resolveCanvasDimensions(sourceWidth, sourceHeight);\n// after — fall back to viewBox when intrinsic width/height are missing\nconst vb = svg.viewBox?.baseVal;\nconst sourceWidth = dimensions?.width || image.naturalWidth || image.width || vb?.width;\nconst sourceHeight = dimensions?.height || image.naturalHeight || image.height || vb?.height;\nif (!sourceWidth || !sourceHeight) throw new Error('Mermaid SVG has no measurable dimensions');\nconst canvasDimensions = resolveCanvasDimensions(sourceWidth, sourceHeight);","handlingStrategy":"validation","validationCode":"// Validate measured dimensions before exporting\nfunction isValidDimensions(w: unknown, h: unknown): boolean {\n  return Number.isFinite(w) && Number.isFinite(h) && (w as number) > 0 && (h as number) > 0;\n}\nif (!isValidDimensions(sourceWidth, sourceHeight)) throw new Error('SVG has no measurable dimensions');","typeGuard":"function isPositiveFinite(n: unknown): n is number {\n  return typeof n === 'number' && Number.isFinite(n) && n > 0;\n}","tryCatchPattern":"try {\n  const dims = resolveCanvasDimensions(sourceWidth, sourceHeight);\n} catch (err) {\n  if (err.message === 'Mermaid diagram has invalid export dimensions') {\n    // fall back to viewBox-derived dimensions or abort export gracefully\n  }\n}","preventionTips":["Measure the SVG after layout/paint, not while it is display:none.","Derive dimensions from the viewBox when width/height attributes are missing.","Pass explicit dimensions from the caller when the diagram has no intrinsic size."],"tags":["mermaid","canvas","export","svg","dimensions","browser"],"backgroundTag":null,"analyzedSha":"5ff282f9006c436e561de1afd39a481bea1ef0d8","analyzedAt":"2026-08-12T21:38:08.145Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}