{"record":{"id":"afce5dee9fe16e79","repo":"transloadit/uppy","slug":"cannot-read-image-probably-an-svg-with-external-r","errorCode":null,"errorMessage":"cannot read image, probably an svg with external resources","messagePattern":"cannot read image, probably an svg with external resources","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"packages/@uppy/thumbnail-generator/src/index.ts","lineNumber":61,"sourceCode":"  type: string,\n  quality: number,\n): Promise<Blob | File> {\n  try {\n    canvas.getContext('2d')!.getImageData(0, 0, 1, 1)\n  } catch (err) {\n    if (err.code === 18) {\n      return Promise.reject(\n        new Error('cannot read image, probably an svg with external resources'),\n      )\n    }\n  }\n\n  if (canvas.toBlob) {\n    return new Promise<Blob | null>((resolve) => {\n      canvas.toBlob(resolve, type, quality)\n    }).then((blob) => {\n      if (blob === null) {\n        throw new Error(\n          'cannot read image, probably an svg with external resources',\n        )\n      }\n      return blob\n    })\n  }\n  return Promise.resolve()\n    .then(() => {\n      return dataURItoBlob(canvas.toDataURL(type, quality), {})\n    })\n    .then((blob) => {\n      if (blob === null) {\n        throw new Error('could not extract blob, probably an old browser')\n      }\n      return blob\n    })\n}\n","sourceCodeStart":43,"sourceCodeEnd":79,"githubUrl":"https://github.com/transloadit/uppy/blob/5d4dedd02a1ac0ae022c75c54aca76558f88e256/packages/@uppy/thumbnail-generator/src/index.ts#L43-L79","documentation":"canvasToBlob throws this when the modern path (canvas.toBlob) resolves with null. Per spec toBlob calls back with null when the canvas is tainted or cannot be encoded — most commonly an SVG containing external resources that taint the canvas, making thumbnail encoding impossible.","triggerScenarios":"ThumbnailGenerator.createThumbnail processing an SVG whose markup references external images/fonts (href to remote assets). The canvas becomes tainted (or encoding fails) and toBlob(resolve) resolves null, triggering the throw inside the .then().","commonSituations":"Users upload SVGs with external <image href> or @import'd fonts; sites accepting image/svg+xml by mimeType; older behavior differences in canvas tainting across browsers.","solutions":["If SVGs don't need thumbnails, exclude them: thumbnail generator's thumbnailType or filter thumbnail generation via forEigenWaitlist — practically, restrict allowed file types or accept the failure","Inline all external resources inside the SVG before upload (data URIs) so the canvas is not tainted","Catch this error in requestThumbnail/on-thumbnail-error handler and skip the thumbnail gracefully","Use a custom thumbnail via uppy.setFilePreview for SVG files instead of canvas rendering"],"exampleFix":"// before\n// user uploads logo.svg referencing https://cdn/.../font.woff -> thumbnail throws\n\n// after\nuppy.on('thumbnail:error', (file, err) => {\n  if (/svg with external resources/.test(err.message)) {\n    uppy.setFilePreview(file.id, fallbackSvgIconDataUri)\n  }\n})","handlingStrategy":"try-catch","validationCode":"function isSafeSvg(file: File): boolean {\n  if (file.type !== 'image/svg+xml') return true\n  return !/xlink:href\\s*=\\s*\"http|href\\s*=\\s*\"http/.test(\n    awaitFirstKbOf(file),\n  ) // rough check for external refs\n}","typeGuard":"null","tryCatchPattern":"uppy.on('thumbnail:error', (file, err) => {\n  if (/svg with external resources/.test(err.message)) {\n    uppy.setFilePreview(file.id, genericPreviewIcon)\n  }\n})","preventionTips":["Provide fallback previews for SVGs","Instruct users to embed (inline) assets in SVGs","Don't rely on thumbnails for SVG-heavy pipelines"],"tags":["thumbnail-generator","svg","canvas-tainted","blob"],"backgroundTag":"canvas-tainted-svg-rendering","analyzedSha":"5d4dedd02a1ac0ae022c75c54aca76558f88e256","analyzedAt":"2026-08-28T12:18:41.267Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}