{"record":{"id":"3e7cbc0c856d3523","repo":"remotion-dev/remotion","slug":"the-waveform-sample-rate-must-be-a-positive-number","errorCode":null,"errorMessage":"The waveform sample rate must be a positive number.","messagePattern":"The waveform sample rate must be a positive number\\.","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/timeline-utils/src/audio-waveform/load-waveform-peaks.ts","lineNumber":42,"sourceCode":"\treadonly completedPeaks: number;\n\treadonly totalPeaks: number;\n\treadonly final: boolean;\n};\n\ntype LoadWaveformPeaksOptions = {\n\treadonly onProgress?: (progress: Progress) => void;\n\treadonly progressIntervalInMs?: number;\n\treadonly waveformSampleRate?: number;\n};\n\nexport async function loadWaveformPeaks(\n\tsrc: string | InputAudioTrack,\n\tsignal: AbortSignal,\n\toptions?: LoadWaveformPeaksOptions,\n): Promise<WaveformResult> {\n\tconst waveformSampleRate = options?.waveformSampleRate ?? TARGET_SAMPLE_RATE;\n\tif (!Number.isFinite(waveformSampleRate) || waveformSampleRate <= 0) {\n\t\tthrow new Error('The waveform sample rate must be a positive number.');\n\t}\n\n\tconst cacheKey = getWaveformCacheKey(src, waveformSampleRate);\n\tconst cached = peaksCache.get(cacheKey);\n\tif (cached) {\n\t\temitWaveformProgress({\n\t\t\tpeaks: cached.peaks,\n\t\t\taverageVolume: cached.averageVolume,\n\t\t\tcompletedPeaks: cached.peaks.length,\n\t\t\ttotalPeaks: cached.peaks.length,\n\t\t\tfinal: true,\n\t\t\tonProgress: options?.onProgress,\n\t\t});\n\t\treturn cached;\n\t}\n\n\tconst input =\n\t\ttypeof src === 'string'","sourceCodeStart":24,"sourceCodeEnd":60,"githubUrl":"https://github.com/remotion-dev/remotion/blob/b2f4e34732f3c6c222ea029413e22dc402218cd7/packages/timeline-utils/src/audio-waveform/load-waveform-peaks.ts#L24-L60","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Pass a positive finite number, e.g. { waveformSampleRate: 100 }","Omit waveformSampleRate entirely to use the built-in default (TARGET_SAMPLE_RATE)","Coerce safely: const rate = Number(cfg.rate); if (!Number.isFinite(rate) || rate <= 0) rate = 100;","Check where the value originates (config file, prop, division) and fix the source producing 0/NaN"],"exampleFix":"// before\nloadWaveformPeaks(url, signal, { waveformSampleRate: cfg.sampleRate ?? 0 })\n// after\nloadWaveformPeaks(url, signal, cfg.sampleRate && Number.isFinite(cfg.sampleRate) && cfg.sampleRate > 0 ? { waveformSampleRate: cfg.sampleRate } : undefined)","handlingStrategy":"validation","validationCode":"function isValidSampleRate(rate: unknown): rate is number {\n  return typeof rate === 'number' && Number.isFinite(rate) && rate > 0;\n}\nconst options = isValidSampleRate(cfg.waveformSampleRate) ? { waveformSampleRate: cfg.waveformSampleRate } : undefined;","typeGuard":"function isValidSampleRate(rate: unknown): rate is number {\n  return typeof rate === 'number' && Number.isFinite(rate) && rate > 0;\n}","tryCatchPattern":"try {\n  const peaks = await loadWaveformPeaks(url, signal, options);\n} catch (err) {\n  if (err instanceof Error && err.message.includes('waveform sample rate must be a positive number')) {\n    return loadWaveformPeaks(url, signal); // fall back to default TARGET_SAMPLE_RATE\n  }\n  throw err;\n}","preventionTips":["Only pass waveformSampleRate when it is a validated positive finite number","Coerce config values with Number() and guard Number.isFinite before use","Rely on the library default (omit the option) unless you specifically need custom resampling","Add a schema check (zod/valibot) for waveformSampleRate: z.number().positive().finite()"],"tags":["validation","audio","waveform","timeline"],"backgroundTag":"invalid-numeric-parameter","analyzedSha":"b2f4e34732f3c6c222ea029413e22dc402218cd7","analyzedAt":"2026-09-09T13:27:51.281Z","contentChangedAt":"2026-09-09T13:27:51.281Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}