{"record":{"id":"64b407aa8e70c774","repo":"yikart/AiToEarn","slug":"no-images-were-generated","errorCode":null,"errorMessage":"No images were generated","messagePattern":"No images were generated","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"project/aitoearn-web/src/components/Chat/Share/ShareModal.tsx","lineNumber":394,"sourceCode":"        console.error('Failed to generate share link:', err)\n        toast.error('Failed to generate share link')\n        return\n      }\n      finally {\n        setGeneratingLink(false)\n      }\n    }\n\n    setGeneratingImage(true)\n    try {\n      const blobs = await generateImageFromMessages(selectedMessages, user?.name, {\n        appTitle: t('appName'),\n        appUrl: t('appUrl'),\n        shareUrl: link || undefined,\n        expiresAt: expiresAt || undefined,\n      })\n      if (!blobs || blobs.length === 0)\n        throw new Error('No images were generated')\n\n      // 直接下载\n      for (let i = 0; i < blobs.length; i++) {\n        const blob = blobs[i]\n        const a = document.createElement('a')\n        const url = URL.createObjectURL(blob)\n        a.href = url\n        a.download\n          = blobs.length === 1\n            ? `aitoearn_conversation_${taskId}.png`\n            : `aitoearn_${taskId}_${i + 1}.png`\n        document.body.appendChild(a)\n        a.click()\n        a.remove()\n        URL.revokeObjectURL(url)\n      }\n      toast.success(t('download'))\n    }","sourceCodeStart":376,"sourceCodeEnd":412,"githubUrl":"https://github.com/yikart/AiToEarn/blob/d3aa8bea5b146a8675607cf0144d891aad3e9683/project/aitoearn-web/src/components/Chat/Share/ShareModal.tsx#L376-L412","documentation":"ShareModal's image download path throws this Error when generateShareImageBlobs (invoked with appTitle/appUrl/shareUrl/expiresAt) returns an empty or null blob array, meaning no share images could be rendered. The throw is caught by the surrounding handler which shows an error to the user instead of downloading files.","triggerScenarios":"Clicking the download action in ShareModal when the canvas/html-to-image generation produced zero blobs — e.g. the share preview node was not mounted, contained cross-origin tainted images, or rendering silently failed.","commonSituations":"Share dialog opened before QR/preview images finished loading; cross-origin images tainting the canvas so toBlob/serialization yields nothing; browser rendering failure in headless or older browsers; shareUrl/expiry state empty.","solutions":["Ensure all images inside the share node are loaded (await image decode/onload) before generating blobs","Serve share images via the same-origin OSS proxy (getOssProxyPath) to avoid canvas tainting","Verify the share preview DOM node is mounted and has non-zero size when generating","Log the generator's return value to find why blobs is empty; add a retry"],"exampleFix":"// before\nconst blobs = await generateShareImageBlobs({ ... })\nif (!blobs || blobs.length === 0)\n  throw new Error('No images were generated')\n// after\nconst blobs = await generateShareImageBlobs({ ... })\nif (!blobs || blobs.length === 0)\n  throw new Error(`No images were generated (link=${link}, expiresAt=${expiresAt})`)","handlingStrategy":"validation","validationCode":"const node = document.querySelector('[data-share-card]')\nif (!node || node.clientWidth === 0) throw new Error('share node not rendered')\nawait Promise.all(Array.from(node.querySelectorAll('img')).map(img => img.decode?.() ?? Promise.resolve()))","typeGuard":"function isBlobArray(v: unknown): v is Blob[] {\n  return Array.isArray(v) && v.length > 0 && v.every(b => b instanceof Blob)\n}","tryCatchPattern":"try {\n  const blobs = await generateShareImageBlobs({...})\n  if (!isBlobArray(blobs)) throw new Error('No images were generated')\n} catch (e) {\n  toast.error(t('share.downloadFailed'))\n}","preventionTips":["Await all image loads inside the share node before rendering to canvas","Proxy cross-origin images via getOssProxyPath to avoid canvas tainting","Verify the share preview is mounted and visible when generating","Test share download in headless/older browsers"],"tags":["canvas","image-generation","download"],"backgroundTag":"canvas-tainted-or-empty","analyzedSha":"d3aa8bea5b146a8675607cf0144d891aad3e9683","analyzedAt":"2026-08-31T14:19:24.185Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}