heygen-com/hyperframes · error · AudioFxRenderError

Audio FX failed for track ${options.trackId}: ${(err as Erro

Error message

Audio FX failed for track ${options.trackId}: ${(err as Error).message}

What it means

Catch-all wrapper thrown by the outer try/catch in applyAudioFxChain() for any error that is NOT already an AudioFxRenderError. The inner catch checks instanceof AudioFxRenderError and re-throws those as-is; everything else (browser crashes, page.evaluate exceptions, network errors, unexpected throws) gets wrapped with the trackId and original message for diagnostics. The finally clause still releases the browser lease and removes the temp directory.

Source

Thrown at packages/engine/src/services/audioFxRender.ts:283

      // byteOffset and byteLength matter: Node pools small allocations, so a
      // short payload decodes into an 8 KiB pool and a view over the whole
      // ArrayBuffer would read kilobytes of unrelated memory at the wrong length.
      const outPlanes = rendered.map((b64) => {
        const buf = Buffer.from(b64, "base64");
        return new Float32Array(buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength));
      });
      if (outPlanes.length === 0 || (outPlanes[0]?.length ?? 0) === 0) {
        throw new AudioFxRenderError(`Audio FX produced no samples for track ${options.trackId}`);
      }
      writeWav(outputWav, interleave(outPlanes), sampleRate, outPlanes.length);
      return outputWav;
    } finally {
      await page.close().catch(() => undefined);
    }
  } catch (err) {
    if (err instanceof AudioFxRenderError) throw err;
    throw new AudioFxRenderError(
      `Audio FX failed for track ${options.trackId}: ${(err as Error).message}`,
    );
  } finally {
    rmSync(hostDir, { recursive: true, force: true });
    await lease.release().catch(() => undefined);
  }
}

export type { HfAudioFxChain };

View on GitHub (pinned to c2996c8626)

Solutions

  1. Read the appended original message: 'Audio FX failed for track X: <original>' — the original message is the real diagnostic.
  2. If 'Target closed' / 'Browser disconnected': check Chrome memory limits, add --disable-dev-shm-usage or increase container memory.
  3. If 'Evaluation failed': debug the runtime script in a standalone browser.
  4. Add retry logic around applyAudioFxChain for transient browser crashes, with a fresh browser lease per attempt.
Defensive patterns

Strategy: try-catch

Try / catch

try {
  await applyAudioFxChain(inputWav, chain, outWav, opts);
} catch (err) {
  if (err instanceof AudioFxRenderError && err.message.includes('Audio FX failed for track')) {
    // extract inner message, check for browser crash / target closed
    const inner = err.message.split(': ').slice(1).join(': ');
    if (inner.includes('Target closed') || inner.includes('disconnected')) {
      // retry with a fresh browser lease
    }
  }
  throw err;
}

Prevention

When it happens

Trigger: Any unhandled exception during page setup, script injection, page.evaluate, or WAV writing that isn't already an AudioFxRenderError. The original error's message is appended to give context. Common inner errors: 'Target closed' (browser crashed), 'Evaluation failed' (JS error in page), 'Navigation timeout'.

Common situations: Headless Chrome crashed (OOM, segfault) during FX processing. The page navigated or closed unexpectedly. A JS error inside the evaluate callback (not the __HF_AUDIO_FX check, which is caught separately) propagated. Puppeteer protocol error due to browser disconnect.

Related errors


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