remotion-dev/remotion · error · Error

The waveform sample rate must be a positive number.

Error message

The waveform sample rate must be a positive number.

What it means

loadWaveformPeaks resamples audio into a Float32Array of peaks at a caller-supplied sample rate (options.waveformSampleRate, defaulting to TARGET_SAMPLE_RATE). It validates the rate up front and throws if it is not a finite number greater than zero, because a zero/negative/NaN rate would make resampling math and the cache key nonsensical. The cache is keyed per sample rate, so the value must be a well-defined positive number.

Source

Thrown at packages/timeline-utils/src/audio-waveform/load-waveform-peaks.ts:42

	readonly completedPeaks: number;
	readonly totalPeaks: number;
	readonly final: boolean;
};

type LoadWaveformPeaksOptions = {
	readonly onProgress?: (progress: Progress) => void;
	readonly progressIntervalInMs?: number;
	readonly waveformSampleRate?: number;
};

export async function loadWaveformPeaks(
	src: string | InputAudioTrack,
	signal: AbortSignal,
	options?: LoadWaveformPeaksOptions,
): Promise<WaveformResult> {
	const waveformSampleRate = options?.waveformSampleRate ?? TARGET_SAMPLE_RATE;
	if (!Number.isFinite(waveformSampleRate) || waveformSampleRate <= 0) {
		throw new Error('The waveform sample rate must be a positive number.');
	}

	const cacheKey = getWaveformCacheKey(src, waveformSampleRate);
	const cached = peaksCache.get(cacheKey);
	if (cached) {
		emitWaveformProgress({
			peaks: cached.peaks,
			averageVolume: cached.averageVolume,
			completedPeaks: cached.peaks.length,
			totalPeaks: cached.peaks.length,
			final: true,
			onProgress: options?.onProgress,
		});
		return cached;
	}

	const input =
		typeof src === 'string'

View on GitHub (pinned to b2f4e34732)

Solutions

  1. Pass a positive finite number, e.g. { waveformSampleRate: 100 }
  2. Omit waveformSampleRate entirely to use the built-in default (TARGET_SAMPLE_RATE)
  3. Coerce safely: const rate = Number(cfg.rate); if (!Number.isFinite(rate) || rate <= 0) rate = 100;
  4. Check where the value originates (config file, prop, division) and fix the source producing 0/NaN

Example fix

// before
loadWaveformPeaks(url, signal, { waveformSampleRate: cfg.sampleRate ?? 0 })
// after
loadWaveformPeaks(url, signal, cfg.sampleRate && Number.isFinite(cfg.sampleRate) && cfg.sampleRate > 0 ? { waveformSampleRate: cfg.sampleRate } : undefined)
Defensive patterns

Strategy: validation

Validate before calling

function isValidSampleRate(rate: unknown): rate is number {
  return typeof rate === 'number' && Number.isFinite(rate) && rate > 0;
}
const options = isValidSampleRate(cfg.waveformSampleRate) ? { waveformSampleRate: cfg.waveformSampleRate } : undefined;

Type guard

function isValidSampleRate(rate: unknown): rate is number {
  return typeof rate === 'number' && Number.isFinite(rate) && rate > 0;
}

Try / catch

try {
  const peaks = await loadWaveformPeaks(url, signal, options);
} catch (err) {
  if (err instanceof Error && err.message.includes('waveform sample rate must be a positive number')) {
    return loadWaveformPeaks(url, signal); // fall back to default TARGET_SAMPLE_RATE
  }
  throw err;
}

Prevention

When it happens

Trigger: Passing LoadWaveformPeaksOptions.waveformSampleRate as 0, a negative number, NaN, Infinity, or a string/undefined-derived value (e.g. Number(undefined)) from the caller; startMainThreadLoad / peaks / defaultPeaks / detailedPeaks funnel the same bad value in.

Common situations: Computing the sample rate from config that failed to load (undefined -> NaN via arithmetic); a JSON config where the field is 0 or missing and a default of 0 is used; unit mismatches (milliseconds vs Hz) yielding tiny or negative values.

Related errors


AI-assisted analysis of remotion-dev/remotion@b2f4e34732 (2026-09-09). Data as JSON: /api/errors/3e7cbc0c856d3523. Report an issue: GitHub.