heygen-com/hyperframes · error

${err instanceof Error ? err.message : String(err)}${detail}

Error message

${err instanceof Error ? err.message : String(err)}${detail}

What it means

Thrown by detectOnPage() as a catch-all wrapper around any failure from page.evaluate(inPageAnalyze). It takes the underlying error's message (or String(err)) and appends collected page-error/console-error strings in parentheses so the cause of an opaque CDP rejection is visible. Common underlying causes: AudioContext.decodeAudioData rejected (unsupported codec, corrupt audio), __hfAnalyze threw, or the page crashed.

Source

Thrown at packages/cli/src/beats/headlessAnalyzer.ts:125

}

// Load the analyzer bundle into the page, run analysis, and surface in-page
// errors (decode/codec failures, missing global) instead of an opaque rejection.
async function detectOnPage(page: Page, bundle: string, b64: string): Promise<HeadlessBeatResult> {
  const pageErrors: string[] = [];
  page.on("pageerror", (e) => {
    pageErrors.push((e as Error).message);
  });
  page.on("console", (m) => {
    if (m.type() === "error") pageErrors.push(m.text());
  });
  await page.setContent("<!doctype html><html><body></body></html>");
  await page.addScriptTag({ content: bundle });
  try {
    return (await page.evaluate(inPageAnalyze, b64)) as HeadlessBeatResult;
  } catch (err) {
    const detail = pageErrors.length ? ` (${pageErrors.join("; ")})` : "";
    throw new Error(`${err instanceof Error ? err.message : String(err)}${detail}`);
  }
}

/** Decode + analyze the given audio bytes in headless Chrome. */
export async function analyzeBeatsHeadless(audioBytes: Buffer): Promise<HeadlessBeatResult> {
  if (audioBytes.length > MAX_AUDIO_BYTES) {
    const mb = Math.round(audioBytes.length / 1e6);
    throw new Error(
      `Audio file too large for headless analysis (${mb}MB > ${MAX_AUDIO_BYTES / 1e6}MB).`,
    );
  }
  const bundle = await buildAnalyzerBundle();
  const { ensureBrowser } = await import("../browser/manager.js");
  const puppeteer = await import("puppeteer-core");
  const browser = await ensureBrowser();
  const chrome: Browser = await puppeteer.default.launch({
    headless: true,
    executablePath: browser.executablePath,

View on GitHub (pinned to c2996c8626)

Solutions

  1. Read the parenthesized detail in the message — it carries the in-page error (e.g. 'Failed to decode audio data').
  2. Convert the audio to a broadly supported format: `ffmpeg -i in.wma -c:a libmp3lame -q:a 2 out.mp3` or to WAV.
  3. Verify the file is a valid audio container: `ffprobe in.mp3`.

Example fix

# before — Chrome cannot decode WMA
$ bunx hyperframes beats clip.wma
# convert to mp3
$ ffmpeg -i clip.wma -c:a libmp3lame -q:a 2 clip.mp3
$ bunx hyperframes beats clip.mp3
Defensive patterns

Strategy: try-catch

Validate before calling

import { execFileSync } from 'node:child_process';
function audioDecodes(p: string): boolean {
  try {
    execFileSync('ffprobe', ['-v', 'error', '-select_streams', 'a', '-show_entries', 'stream=codec_name', '-of', 'csv=p=0', p], { encoding: 'utf-8' });
    return true;
  } catch { return false; }
}
if (!audioDecodes(inputPath)) throw new Error('Audio file is not decodable; convert to mp3/wav.');

Try / catch

try {
  await analyzeBeatsHeadless(buf);
} catch (err) {
  const msg = (err as Error).message;
  if (/decode|audio/i.test(msg)) {
    // convert to mp3 and retry
  }
  throw err;
}

Prevention

When it happens

Trigger: analyzeBeatsHeadless() calls detectOnPage(page, bundle, b64); page.evaluate throws because the audio bytes could not be decoded by the Web Audio decoder (e.g. a .wma or obscure codec), or inPageAnalyze threw for any reason.

Common situations: Input audio is in a format Chrome's Web Audio cannot decode (e.g. WMA, ATRAC, some FLAC variants on older Chrome); the audio buffer is truncated/corrupt; a transient page-level JS error occurred during analysis.

Related errors


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