heygen-com/hyperframes · error

--zoom selector matched no element: ${target.selector}

Error message

--zoom selector matched no element: ${target.selector}

What it means

Thrown by resolveCropRegion() when a --zoom target of kind 'selector' is resolved but document.querySelector(selector) returned null at capture time — the element did not exist in the DOM when the frame was sampled. The pipeline deliberately fails loud rather than silently falling back to a full-frame crop, because a silent fallback would produce a misleading zoom that looks like a bug elsewhere. The offending selector is included.

Source

Thrown at packages/cli/src/capture/captureCompositionFrame.ts:468

// clamping leaves a pixel-wide remnant. Either way the crop would be a sliver
// that tells an agent nothing, so the final clamped region is what's guarded
// and callers skip the frame on null. Explicit x,y,w,h regions stay literal.
const MIN_CROP_REGION_PX = 8;

export async function resolveCropRegion(
  page: ZoomSelectorPage,
  target: ZoomTarget,
  canvas: CropCanvas,
  paddingPx = DEFAULT_ZOOM_PADDING_PX,
): Promise<CropRegion | null> {
  if (target.kind === "region") return clampCropRegion(target.region, canvas);
  const bbox = await page.evaluate((selector) => {
    const element = document.querySelector(selector);
    if (!element) return null;
    const rect = element.getBoundingClientRect();
    return { x: rect.x, y: rect.y, width: rect.width, height: rect.height };
  }, target.selector);
  if (!bbox) throw new Error(`--zoom selector matched no element: ${target.selector}`);
  const region = padCropRegion(bbox, canvas, paddingPx);
  if (region.width < MIN_CROP_REGION_PX || region.height < MIN_CROP_REGION_PX) return null;
  return region;
}

export interface CropCapturePage {
  viewport(): { width: number; height: number; deviceScaleFactor?: number } | null;
  setViewport(viewport: {
    width: number;
    height: number;
    deviceScaleFactor?: number;
  }): Promise<void>;
  screenshot(options: { clip: CropRegion; type: "png"; omitBackground: true }): Promise<Uint8Array>;
}

/**
 * Capture a high-density crop of `region`: raise `deviceScaleFactor` to
 * `scale`, take a clip screenshot, then restore the original viewport.

View on GitHub (pinned to c2996c8626)

Solutions

  1. Verify the selector matches at the capture timecode: open the composition in a browser at that frame and run document.querySelector('<selector>') in devtools.
  2. Use a selector that is stable across the timeline, or switch to an explicit region (--zoom x,y,w,h) if the element moves.
  3. If the element is shadow-DOM scoped, use a selector that pierces it or restructure the composition.
  4. Confirm the element exists at the exact frame being captured (not just at t=0).

Example fix

// before — selector does not match at capture time
--zoom .stat-value  // element only appears after a fragment reveal
// option A: use a stable selector
--zoom #hero-title
// option B: use an explicit region (in px)
--zoom 120,80,640,360
Defensive patterns

Strategy: validation

Validate before calling

// Before capture, verify the selector resolves at the target timecode in a preview run.
const exists = await page.evaluate((sel) => !!document.querySelector(sel), selector);
if (!exists) {
  throw new Error(`Selector not present at this timecode: ${selector}`);
}

Try / catch

try {
  await resolveCropRegion(page, target, canvas);
} catch (err) {
  if (/--zoom selector matched no element/i.test((err as Error).message)) {
    // fall back to an explicit region or skip the frame
  }
  throw err;
}

Prevention

When it happens

Trigger: A --zoom selector target is evaluated via page.evaluate; document.querySelector(target.selector) returns null. Happens when the element is conditionally rendered, behind a fragment that hasn't mounted yet, mistyped, or removed from the composition since the selector was authored.

Common situations: Selector references a class/ID that was renamed; element exists only after a fragment reveal that hasn't fired at the sampled timecode; typo in the selector; element is inside a shadow DOM that querySelector can't cross; element only appears in a different slide/scene.

Related errors


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