heygen-com/hyperframes · error · FigmaClientError

RENDER_FAILED

RENDER_FAILED

Error message

figma could not render node ${nodeId} as ${opts.format}

What it means

Thrown in the batch render loop of runAssetImportMany() when figma's /v1/images response omits a node or returns a null/empty url for it. Unlike a plain Error, this is a FigmaClientError with code 'RENDER_FAILED' — the typed code is what lets component import's rasterizeFallback catch it, retry as png, and ultimately skip the node gracefully instead of aborting the whole import.

Source

Thrown at packages/cli/src/commands/figma/asset.ts:209

  const entity = normalizeMeta(opts.entity);

  // Resolve cache hits first; batch-render only the misses.
  const slots: (AssetImportResult | null)[] = refs.map((r) =>
    reuseExisting(fileKey, r.nodeId, opts, version, deps, description, entity),
  );
  const missIndexes = slots.flatMap((s, i) => (s === null ? [i] : []));
  try {
    if (missIndexes.length > 0) {
      const missNodeIds = missIndexes.map((i) => refs[i]!.nodeId);
      const rendered = await deps.client.renderNodes(fileKey, missNodeIds, opts);
      const byNode = new Map(rendered.map((r) => [r.nodeId, r] as const));
      for (const i of missIndexes) {
        const nodeId = refs[i]!.nodeId;
        const r = byNode.get(nodeId);
        // Keep the typed code: component import's rasterize fallback skips on
        // RENDER_FAILED, so a plain Error here would abort the whole import.
        if (!r || r.url === null)
          throw new FigmaClientError(
            "RENDER_FAILED",
            `figma could not render node ${nodeId} as ${opts.format}`,
            undefined,
            "images",
          );
        slots[i] = await freezeAndRecord(
          fileKey,
          nodeId,
          r.url,
          r.ext,
          opts,
          version,
          deps,
          description,
          entity,
        );
      }
    }

View on GitHub (pinned to c2996c8626)

Solutions

  1. Retry the node as png (component import does this automatically via renderWithPngRetry)
  2. For asset import, re-run with --format png
  3. If still failing, component import skips it with a placeholder; accept the gap or simplify the node in figma

Example fix

// before: svg render refused for a nested instance
hyperframes figma asset AAA:1:2 --format svg
// after: fall back to png
hyperframes figma asset AAA:1:2 --format png
Defensive patterns

Strategy: fallback

Type guard

import { FigmaClientError } from '@hyperframes/core/figma';
function isRenderFailed(err: unknown): err is FigmaClientError {
  return err instanceof FigmaClientError && err.code === 'RENDER_FAILED';
}

Try / catch

async function importWithPngFallback(ref: string, opts: AssetImportOptions, deps: AssetImportDeps) {
  for (const format of ['svg', 'png'] as const) {
    try {
      return await runAssetImport(ref, { ...opts, format }, deps);
    } catch (err) {
      if (!(err instanceof FigmaClientError) || err.code !== 'RENDER_FAILED') throw err;
    }
  }
  return null; // both formats refused — caller decides whether to skip
}

Prevention

When it happens

Trigger: figma cannot render the node in the requested format (nested instances commonly fail as svg); the node was deleted or changed between the fileVersion check and the render; an unsupported format for that node type; the node id is stale.

Common situations: Complex/nested component instances exported as svg; a node id copied from an old version of the file; selecting a node type figma refuses to rasterize in the chosen format.

Related errors


AI-assisted analysis of heygen-com/hyperframes@c2996c8626 (2026-08-12). Data as JSON: /api/errors/16425d14f8d9f135. Report an issue: GitHub.