heygen-com/hyperframes · error · AudioFxRenderError
WAV has no data chunk: ${path}
Error message
WAV has no data chunk: ${path} What it means
readWav() found a valid `RIFF` header but readWavChunks() walked the chunk list without encountering a `data` chunk. The WAV is structurally incomplete: it has a RIFF container (and possibly a `fmt ` chunk) but no PCM payload to decode. The reader refuses to guess rather than emit silence.
Source
Thrown at packages/engine/src/services/audioFxRender.ts:75
head.channels = buf.readUInt16LE(offset + 10);
head.sampleRate = buf.readUInt32LE(offset + 12);
head.bits = buf.readUInt16LE(offset + 22);
} else if (id === "data") {
data = buf.subarray(offset + 8, Math.min(buf.length, offset + 8 + size));
break;
}
offset += 8 + size + (size % 2);
}
return { ...head, data };
}
export function readWav(path: string): WavData {
const buf = readFileSync(path);
if (buf.length < 44 || buf.toString("ascii", 0, 4) !== "RIFF") {
throw new AudioFxRenderError(`Not a WAV file: ${path}`);
}
const { format, channels, sampleRate, bits, data } = readWavChunks(buf);
if (!data) throw new AudioFxRenderError(`WAV has no data chunk: ${path}`);
return { samples: decodeSamples(data, format, bits, path), sampleRate, channels };
}
/** Interleaved samples as floats, for the two formats the mixer emits upstream. */
function decodeSamples(data: Buffer, format: number, bits: number, path: string): Float32Array {
if (format === 3 && bits === 32) {
const n = Math.floor(data.length / 4);
// A Float32Array view demands a 4-aligned offset, and chunk layouts that put
// `data` on an odd boundary (an 18-byte fmt plus a fact chunk, which
// ffmpeg's pcm_f32le writes) would otherwise throw RangeError. Copy then.
if (data.byteOffset % 4 === 0) return new Float32Array(data.buffer, data.byteOffset, n);
const copied = new Float32Array(n);
for (let i = 0; i < n; i++) copied[i] = data.readFloatLE(i * 4);
return copied;
}
if (format === 1 && bits === 16) {
const n = Math.floor(data.length / 2);
const out = new Float32Array(n);View on GitHub (pinned to c2996c8626)
Solutions
- Inspect the chunk layout: `ffprobe <path>` should report a PCM stream with a non-zero duration; if duration is N/A, the data chunk is missing or empty.
- Re-run the upstream encode/mix step that produced the WAV so it completes and flushes the data chunk.
- If the file is a metadata stub, regenerate the actual audio asset.
- Verify file size matches expected duration × sampleRate × channels × bits/8.
Example fix
# before $ ffprobe broken.wav # -> Duration: N/A, no audio stream # after: re-encode so the data chunk is written $ ffmpeg -i source.mov -c:a pcm_s16le -ar 48000 -ac 2 broken.wav $ ffprobe broken.wav # -> Duration: 00:00:12.00, pcm_s16le
Defensive patterns
Strategy: try-catch
Validate before calling
import { readFileSync } from "node:fs";
function wavHasDataChunk(path: string): boolean {
let buf;
try { buf = readFileSync(path); } catch { return false; }
if (buf.length < 12 || buf.toString("ascii", 0, 4) !== "RIFF") return false;
let off = 12;
while (off + 8 <= buf.length) {
if (buf.toString("ascii", off, off + 4) === "data") return true;
const size = buf.readUInt32LE(off + 4);
off += 8 + size + (size % 2);
}
return false;
}
if (!wavHasDataChunk(path)) throw new Error(`WAV missing data chunk: ${path}`); Type guard
function isCompleteWav(path: string): boolean {
return wavHasDataChunk(path); // same helper as validationCode
} Try / catch
import { AudioFxRenderError } from "@hyperframes/engine/services/audioFxRender";
try {
return readWav(path);
} catch (e) {
if (e instanceof AudioFxRenderError && /no data chunk/.test(e.message)) {
throw new Error(`audio asset ${path} is incomplete (no data chunk); re-run the upstream encode`, { cause: e });
}
throw e;
} Prevention
- Confirm `ffprobe <path>` reports a non-N/A duration before reading.
- Re-run interrupted upstream encodes rather than retrying readWav on the partial file.
- Verify file size is at least duration × sampleRate × channels × bits/8.
When it happens
Trigger: A WAV with only a `fmt ` chunk and no `data` chunk (some metadata extractors emit these), a truncated file whose `data` chunk was never written, a file whose chunk IDs are non-standard so the walker skips the payload, or a file where the `data` chunk sits beyond EOF due to truncation.
Common situations: An interrupted encode that wrote the header but not the samples; a metadata-only WAV exported by a tag editor; an upstream FFmpeg run killed mid-write; a file copied incompletely (rsync interrupted).
Related errors
- Not a WAV file: ${path}
- Unsupported WAV format ${format}/${bits}-bit: ${path}
- [build-zip] ${label} at ${path} is too short — read ${bytesR
- Audio file too large for headless analysis (${mb}MB > ${MAX_
- ffmpeg is required to extract audio from video. Install: ${g
AI-assisted analysis of heygen-com/hyperframes@c2996c8626 (2026-08-12).
Data as JSON: /api/errors/e9298bd83883671e.
Report an issue: GitHub.