{"record":{"id":"903cbb432a989893","repo":"linshenkx/prompt-optimizer","slug":"canvas-is-not-available","errorCode":null,"errorMessage":"Canvas is not available","messagePattern":"Canvas is not available","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/ui/src/utils/favorite-share-export.ts","lineNumber":932,"sourceCode":"        } else {\n          fail();\n        }\n      });\n    }());\n  </script>\n</body>\n</html>`\n\n  return {\n    blob: new Blob([html], { type: 'text/html;charset=utf-8' }),\n    result,\n  }\n}\n\nconst ensureCanvas = (canvasFactory?: () => HTMLCanvasElement): HTMLCanvasElement => {\n  const canvas = canvasFactory?.() || document.createElement('canvas')\n  if (!canvas.getContext) {\n    throw new Error('Canvas is not available')\n  }\n  return canvas\n}\n\nconst wrapCanvasText = (\n  context: CanvasRenderingContext2D,\n  text: string,\n  maxWidth: number,\n): string[] => {\n  const lines: string[] = []\n  for (const rawLine of text.split(/\\r?\\n/)) {\n    const words = rawLine.split(/(\\s+)/).filter(Boolean)\n    let line = ''\n    for (const word of words) {\n      if (context.measureText(word).width > maxWidth) {\n        for (const char of Array.from(word)) {\n          const next = `${line}${char}`\n          if (line && context.measureText(next).width > maxWidth) {","sourceCodeStart":914,"sourceCodeEnd":950,"githubUrl":"https://github.com/linshenkx/prompt-optimizer/blob/3e677b1d9f7e0493c142c175560531e7ae786dce/packages/ui/src/utils/favorite-share-export.ts#L914-L950","documentation":"Thrown by ensureCanvas in packages/ui/src/utils/favorite-share-export.ts when neither the provided canvasFactory nor document.createElement('canvas') yields an object with a getContext method. This is an environment-capability guard: in normal browsers a canvas always has getContext, so hitting it means canvas support is absent or the factory returned something invalid. It fires before any 2D rendering begins.","triggerScenarios":"Running the PNG share-image export in an environment without DOM/canvas (SSR, Node, jsdom, Web Workers without DOM access); passing a canvasFactory that returns null, undefined, a plain object, or a detached mock lacking getContext; or an environment where HTMLCanvasElement is not implemented.","commonSituations":"Unit tests in jsdom that trigger image export; server-side rendering paths that accidentally call share-image generation; mocking document.createElement without providing getContext; embedded webviews with canvas disabled. Note the factory result is used as-is, so a falsy factory result silently falls back to document.createElement — the error only fires when both paths fail.","solutions":["If in tests, pass a canvasFactory returning a real or adequately mocked canvas (with getContext and a 2D context stub)","Guard the export call: only invoke PNG share export when typeof document !== 'undefined' and document.createElement('canvas').getContext exists","In SSR, run the export only after mount in the browser, or use a node-canvas-backed factory","Fix a canvasFactory that returns a non-canvas object (e.g. a context instead of the canvas)"],"exampleFix":"// before\nconst canvas = ensureCanvas(() => fakeCanvasStub) // stub lacks getContext -> throws Canvas is not available\n\n// after\nconst canvas = ensureCanvas(() => realCanvas) // or omit factory in a real browser DOM\nconst context = canvas.getContext('2d')\nif (!context) throw new Error('Canvas 2D context is not available')","handlingStrategy":"validation","validationCode":"const canUseCanvas = (): boolean =>\n  typeof document !== 'undefined' &&\n  typeof document.createElement === 'function' &&\n  typeof document.createElement('canvas').getContext === 'function'\n\nif (!canUseCanvas()) {\n  // hide PNG share button or fall back to text sharing\n}","typeGuard":"const isCanvasLike = (el: unknown): el is HTMLCanvasElement =>\n  typeof el === 'object' && el !== null && typeof (el as HTMLCanvasElement).getContext === 'function'","tryCatchPattern":"try {\n  const blob = await exportFavoriteSharePng(options)\n} catch (e) {\n  if (e instanceof Error && e.message === 'Canvas is not available') {\n    // fall back to text-only share, or disable the feature in this environment\n    return\n  }\n  throw e\n}","preventionTips":["Only trigger share-image export in a real browser DOM (guard typeof document)","In tests, pass a canvasFactory returning a properly mocked canvas","Don't invoke canvas export paths during SSR; defer to client-side after mount","Ensure canvasFactory returns the canvas element itself, not a context or null"],"tags":["canvas","browser-environment","ssr","share-export"],"backgroundTag":"canvas-not-supported","analyzedSha":"3e677b1d9f7e0493c142c175560531e7ae786dce","analyzedAt":"2026-08-27T21:29:16.709Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}