heygen-com/hyperframes · error · AudioFxRenderError

Audio FX produced no samples for track ${options.trackId}

Error message

Audio FX produced no samples for track ${options.trackId}

What it means

Thrown when the browser-side audio FX render returns zero output planes or an empty first plane. After decoding the base64-encoded Float32 arrays back from the page, the code checks outPlanes.length === 0 or outPlanes[0]?.length === 0. A successful render must produce at least one non-empty sample plane; silence or an empty result indicates the FX chain consumed all input without producing output.

Source

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

        },
        [
          planes.map((plane) =>
            Buffer.from(plane.buffer, plane.byteOffset, plane.length * 4).toString("base64"),
          ),
          sampleRate,
          JSON.stringify(chain),
        ] as [string[], number, string],
      )) as string[];

      // 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. Log the chainJson and the number of input planes/samples to verify the chain is well-formed.
  2. Test the FX chain in isolation in a browser with the same input WAV to see if output is genuinely empty.
  3. Check enabledAudioFxNodes() output for unexpected or misconfigured nodes.
  4. If a gain/gate effect is intentional, ensure it doesn't reduce output to exactly zero-length — a silence plane should still have sample-count matching input.
Defensive patterns

Strategy: validation

Try / catch

try {
  await applyAudioFxChain(inputWav, chain, outWav, opts);
} catch (err) {
  if (err instanceof AudioFxRenderError && err.message.includes('produced no samples')) {
    // test chain in isolation, check for silencing nodes
  }
  throw err;
}

Prevention

When it happens

Trigger: The page.evaluate call to api.render(channelB64, rate, chainJson) resolved successfully, but the returned array is empty or contains only empty Float32Arrays. This can happen if the FX runtime has a bug in its output encoding, if the chainJson describes a chain that produces zero-length output, or if a gain/node silences the signal to exactly zero samples.

Common situations: A custom AudioFxNode has a bug that returns an empty buffer. The chain JSON is malformed enough to pass validation but produces no output. The base64 round-trip between page and Node lost data (though that more likely causes a different decode error). A gate/expander node with extreme settings eliminates all samples.

Related errors


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