{"record":{"id":"beed6a5bdd313216","repo":"heygen-com/hyperframes","slug":"figma-render-returned-non-svg-bytes-for-an-svg-exp","errorCode":null,"errorMessage":"figma render returned non-SVG bytes for an svg export — retry the import","messagePattern":"figma render returned non-SVG bytes for an svg export — retry the import","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/cli/src/commands/figma/asset.ts","lineNumber":133,"sourceCode":" * times). */\nasync function freezeAndRecord(\n  fileKey: string,\n  nodeId: string,\n  url: string,\n  ext: FigmaAssetFormat,\n  opts: AssetImportOptions,\n  version: string,\n  deps: AssetImportDeps,\n  description: string | undefined,\n  entity: string | undefined,\n): Promise<AssetImportResult> {\n  let bytes = await deps.download(url);\n  if (ext === \"svg\") {\n    // Sniff before decoding: an SVG starts with '<' or an XML decl/BOM. A\n    // non-text payload would decode to U+FFFD soup and still write to disk.\n    const b0 = bytes[0];\n    if (b0 !== 0x3c && b0 !== 0x3f && b0 !== 0xef)\n      throw new Error(\"figma render returned non-SVG bytes for an svg export — retry the import\");\n    bytes = new TextEncoder().encode(sanitizeSvg(new TextDecoder().decode(bytes)));\n  }\n  const id = nextId(deps.projectDir, \"image\");\n  const destAbs = join(typeDirPath(deps.projectDir, \"image\"), `${id}.${ext}`);\n  freezeBytes(bytes, destAbs);\n  const record: FigmaManifestRecord = {\n    id,\n    type: \"image\",\n    path: relative(deps.projectDir, destAbs),\n    source: `figma:${fileKey}/${nodeId}`,\n    ...(description !== undefined && { description }),\n    ...(entity !== undefined && { entity }),\n    provenance: {\n      source: \"figma\",\n      fileKey,\n      nodeId,\n      version,\n      format: opts.format,","sourceCodeStart":115,"sourceCodeEnd":151,"githubUrl":"https://github.com/heygen-com/hyperframes/blob/c2996c8626135db5253519359d8a063d3bafad8d/packages/cli/src/commands/figma/asset.ts#L115-L151","documentation":"Thrown inside freezeAndRecord() before decoding an SVG export. It sniffs the first byte of the downloaded payload: a valid SVG starts with '<' (0x3c), an XML declaration '<?xml' (0x3f), or a UTF-8 BOM (0xef). Any other leading byte means figma did not return SVG (e.g. a PNG/JPEG binary, or an HTML/text error page), so decoding would produce U+FFFD soup that still gets written to disk. The message instructs a retry because the cause is usually transient.","triggerScenarios":"figma's /v1/images endpoint returned a non-SVG body for an svg-format request: a transient render glitch, an error HTML page (first byte '<' would pass though), a PNG (0x89), JPEG (0xff), or a rate-limit/auth text response. The guard specifically catches binary/HTML masquerading as SVG.","commonSituations":"A momentary figma render hiccup; a node too complex to export as vector so figma falls back to raster bytes; a CDN edge serving stale/wrong content-type.","solutions":["Re-run the same import command — the message explicitly says 'retry the import'","If it persists, switch --format to png for that node","Check figma status / the node's renderability in the figma UI"],"exampleFix":"// before: transient svg render glitch\nhyperframes figma asset aBcDeF:1:2 --format svg\n// after: re-run, or fall back to png if it persists\nhyperframes figma asset aBcDeF:1:2 --format svg   # retry once more\nhyperframes figma asset aBcDeF:1:2 --format png    # if svg keeps failing","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"async function importSvgWithRetry(ref: string, opts: AssetImportOptions, deps: AssetImportDeps) {\n  for (let attempt = 0; attempt < 3; attempt += 1) {\n    try {\n      return await runAssetImport(ref, { ...opts, format: 'svg' }, deps);\n    } catch (err) {\n      if (attempt === 2 || !(err instanceof Error) || !err.message.includes('non-SVG bytes')) throw err;\n    }\n  }\n  throw new Error('svg import failed after retries');\n}","preventionTips":["Treat a non-SVG-bytes error as transient — retry once or twice before changing approach","Keep a png fallback ready for nodes that persistently fail svg export","Log the first byte you observe if you instrument downloads, to confirm the sniff"],"tags":["figma","svg","asset","byte-sniff","retry"],"backgroundTag":null,"analyzedSha":"c2996c8626135db5253519359d8a063d3bafad8d","analyzedAt":"2026-08-12T22:18:56.877Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}