Generated WAV downloads from `serve` contain placeholder RIFF/data chunk sizes

Author: davidvk89Created Jul 27, 2026Updated Jul 27, 2026

Summary

Hi! While using Pocket TTS through uvx pocket-tts serve, I noticed that downloaded/generated WAV files contain valid short PCM audio, but the WAV header keeps a placeholder-sized frame/data count.

The audio itself plays in tolerant players/editors, but strict readers may report the file as extremely long or malformed.

Environment

  • OS: Windows
  • Launch method: uvx pocket-tts serve
  • Pocket TTS version: 2.1.0
  • Runtime: uv/uvx-managed Python environment
  • uv version: uv 0.11.32 (3010295ae 2026-07-23 x86_64-pc-windows-msvc)
  • uvx version: uvx 0.11.32 (3010295ae 2026-07-23 x86_64-pc-windows-msvc)
  • uvx-managed Python: 3.14.6
  • Python executable: C:\Users\Gebruiker\AppData\Local\\\uv\cache\archive-v0\tJQCxny2oyLPs0QZ\Scripts\python.exe
  • System Python: not installed / not on PATH
  • Python launcher py: not installed / not on PATH
  • Output path: local served web UI download
  • Audio format observed: mono, 24 kHz, 16-bit PCM
  • Voice mode: uploaded/custom voice prompt

Because system Python and the py launcher are not installed/on PATH, this appears to be running entirely through the uvx-managed Pocket TTS environment.

Observed behavior

Multiple generated WAV files have these header values:

RIFF chunk size: 2000000036
data chunk size: 2000000000
reported frame count: 1000000000

For mono 16-bit PCM, 1_000_000_000 frames corresponds exactly to:

1,000,000,000 frames × 2 bytes = 2,000,000,000 bytes

So this looks like a streaming placeholder frame count being written into the saved WAV file.

Examples

Example 1:

file size: 94124 bytes
RIFF size in header: 2000000036
data chunk size in header: 2000000000
actual data bytes after data chunk header: 94080
format: mono, 24000 Hz, 16-bit PCM
actual duration from payload: ~1.96 seconds
reported duration from header: ~41666.67 seconds

Example 2:

file size: 132524 bytes
RIFF size in header: 2000000036
data chunk size in header: 2000000000
actual data bytes after data chunk header: 132480
format: mono, 24000 Hz, 16-bit PCM
actual duration from payload: ~2.76 seconds
reported duration from header: ~41666.67 seconds

Example 3:

file size: 94124 bytes
RIFF size in header: 2000000036
data chunk size in header: 2000000000
actual data bytes after data chunk header: 94080
format: mono, 24000 Hz, 16-bit PCM
actual duration from payload: ~1.96 seconds
reported duration from header: ~41666.67 seconds

Expected behavior

Downloaded WAV files are readable as normal short WAV files by common audio tools.

Possible source

This appears related to the streaming WAV writer using a placeholder frame count:

python
self.wave_writer.setnframes(1_000_000_000)

That value explains the observed 2_000_000_000 byte data chunk size for mono 16-bit output.

It also looks like header patching is intentionally disabled for unseekable streams:

python
# do not update the header for unseekable streams
self.wave_writer._patchheader = lambda: None
self.wave_writer.close()

So the placeholder header is preserved in the downloaded WAV.

Minimal header inspection snippet

python
from pathlib import Path
import struct
import wave

path = Path("generated_speech.wav")
data = path.read_bytes()

riff_size = struct.unpack_from("<I", data, 4)[0]
data_pos = data.find(b"data")
data_size = struct.unpack_from("<I", data, data_pos + 4)[0]

print("file size:", len(data))
print("RIFF size:", riff_size)
print("data chunk size:", data_size)

with wave.open(str(path), "rb") as w:
    print("params:", w.getparams())
    print("duration from header:", w.getnframes() / w.getframerate())

Impact

The audio payload appears usable, and rewriting the WAV header fixes the files locally.

I’m reporting this because the placeholder value seems to persist in saved downloads, and some tools may interpret the file duration from the header rather than the actual file length.

Possible fix direction

For a downloadable WAV response, maybe the server could either:

  • buffer the complete audio and write a normal seekable WAV with corrected header sizes, or
  • provide a separate non-streaming download route, or
  • patch the header when the output target is seekable/finalized.

Thanks for the project. This was easy to work around locally once found, but I figured it was worth reporting because the placeholder value leaks into saved files in a reproducible way.