heygen-com/hyperframes · error · Error

Render failed for variant "${variant.label}" (${variant.disp

Error message

Render failed for variant "${variant.label}" (${variant.displayPath}): ${normalizeErrorMessage(err)}

What it means

The outer catch in renderCompareVariant(): it wraps EVERY failure inside the per-variant render pipeline — bundleToSingleHtml, serveStaticProjectHtml, openSettledCompositionPage (Puppeteer/Chrome), seekCompositionTimeline, and page.screenshot — into one Error tagged with the variant label, displayPath, and the normalized inner message. It is a catch-all, so the inner cause is what matters.

Source

Thrown at packages/cli/src/commands/compare.ts:299

        renderReadyTimedOut,
      } = await openSettledCompositionPage(html, server.url, {
        renderReadyTimeoutMs: opts.timeoutMs,
        renderReadyWarningSuffix: `comparison variant "${variant.label}" may be inaccurate`,
      });
      try {
        if (opts.atSeconds > 0) {
          await seekCompositionTimeline(page, opts.atSeconds);
        }
        await page.screenshot({ path: opts.framePath, type: "png" });
        return { framePath: opts.framePath, renderReadyTimedOut };
      } finally {
        await chromeBrowser.close();
      }
    } finally {
      await server.close();
    }
  } catch (err) {
    throw new Error(
      `Render failed for variant "${variant.label}" (${variant.displayPath}): ${normalizeErrorMessage(err)}`,
    );
  }
}

async function renderCompareSheet(parsed: ParsedCompareArgs): Promise<CompareSuccessPayload> {
  const capResult = capCompareVariants(parsed.variants);
  const variants = capResult.variants;
  const prepared = prepareCompareVariantProjects(variants);
  const frameDir = mkdtempSync(join(tmpdir(), "hf-compare-frames-"));
  const framePaths: string[] = [];

  try {
    let renderReadyTimedOut = false;
    for (let i = 0; i < prepared.length; i++) {
      const variant = prepared[i]!;
      const framePath = join(frameDir, `variant-${String(i + 1).padStart(2, "0")}.png`);
      const rendered = await renderCompareVariant(variant, {

View on GitHub (pinned to c2996c8626)

Solutions

  1. Read the normalized inner message in the thrown error — it names the actual root cause
  2. Run `hyperframes lint` and `hyperframes check` on the failing variant composition
  3. Verify Chrome is installed and the --out directory is writable
  4. Lower --at to a value within the composition duration
Defensive patterns

Strategy: try-catch

Try / catch

try {
  await renderCompareVariant(variant, opts);
} catch (err) {
  // The wrapper already includes label + displayPath + inner cause.
  // Inspect err.message for the normalized root cause before deciding.
  console.error(`compare variant ${variant.label} failed:`, (err as Error).message);
  throw err;
}

Prevention

When it happens

Trigger: Composition HTML is malformed so bundling fails; Chrome/Puppeteer is missing or crashes; the static project server cannot bind its port; seekCompositionTimeline fails (no GSAP timeline / no seek adapter registered on window.__timelines); the screenshot path is unwritable; --at is beyond the timeline duration.

Common situations: Chrome not installed in CI; a variant composition missing data-* attributes or shipping broken JS; --out pointing at a read-only or non-existent directory; a very short timeline combined with a large --at.

Related errors


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