No module named 'torchaudio.io' (fix)

from torchaudio.io import StreamReader raises ModuleNotFoundError: No module named 'torchaudio.io' on torchaudio 2.9 and newer (or module 'torchaudio' has no attribute 'io'). We tested the TorchCodec replacements for reading and writing, and the pin-2.8 route with its FFmpeg catch.

1. The error

import torchaudio
print("torchaudio", torchaudio.__version__)
from torchaudio.io import StreamReader

torchaudio 2.9.0:

torchaudio 2.9.0+cpu
Traceback (most recent call last):
  File "b1.py", line 3, in <module>
    from torchaudio.io import StreamReader
ModuleNotFoundError: No module named 'torchaudio.io'

torchaudio 2.8.0 imports it fine:

torchaudio 2.8.0+cu128

import torchaudio; torchaudio.io gives the AttributeError variant of the same thing. The torchaudio.io streaming API (StreamReader, StreamWriter) was removed in 2.9; TorchCodec replaces it.

2. Fix: decode with torchcodec AudioDecoder

torchcodec must match your torch (0.8/0.9 for torch 2.9) and needs FFmpeg 4–8 shared libraries; see Could not load libtorchcodec if it won't import. torch 2.9.0, torchcodec 0.9.1, FFmpeg 7, on a 1-second 16 kHz mono WAV:

from torchcodec.decoders import AudioDecoder
dec = AudioDecoder("tone.wav")
print(dec.metadata.sample_rate, dec.metadata.num_channels, dec.metadata.duration_seconds)
samples = dec.get_all_samples()
print(samples.data.shape, samples.sample_rate)
16000 1 1.0
torch.Size([1, 16000]) 16000

samples.data is a float32 (channels, samples) tensor, the same layout torchaudio.load returns. For chunked reading, dec.get_samples_played_in_range(start, stop) takes seconds.

3. Fix: encode with torchcodec AudioEncoder (replaces StreamWriter)

import torch
from torchcodec.encoders import AudioEncoder
t = torch.linspace(0, 1, 16000)
wave = (0.3 * torch.sin(2 * torch.pi * 440 * t)).unsqueeze(0)   # (channels, samples)
AudioEncoder(wave, sample_rate=16000).to_file("out.flac")
from torchcodec.decoders import AudioDecoder
print(AudioDecoder("out.flac").get_all_samples().data.shape)
torch.Size([1, 16000])

4. Or pin torchaudio 2.8.0 — but mind the FFmpeg version

pip install "torch==2.8.0" "torchaudio==2.8.0" brings torchaudio.io back. Actually reading needs FFmpeg too, and 2.8.0 only looks for FFmpeg 4, 5 or 6:

from torchaudio.io import StreamReader
r = StreamReader("tone.wav")
r.add_basic_audio_stream(frames_per_chunk=16000)
for (chunk,) in r.stream():
    print(chunk.shape)

With no FFmpeg, and again with FFmpeg 7 libraries on LD_LIBRARY_PATH, we got the same error:

Traceback (most recent call last):
  ...
ImportError: Failed to intialize FFmpeg extension. Tried versions: ['6', '5', '4', '']. Enable DEBUG logging to see more details about the error.

So on the 2.8 route install FFmpeg 6 or older (e.g. conda install -c conda-forge "ffmpeg<7"). TorchCodec accepts 4–8. Full walkthrough: Failed to intialize FFmpeg extension.

Related: No module named torchaudio.backend · torchaudio has no attribute info · torchaudio has no attribute AudioMetaData · torchaudio sox_effects: libsox.so not found

Frequently asked questions

Which torchaudio version removed torchaudio.io?

In our test from torchaudio.io import StreamReader works on 2.8.0 and raises ModuleNotFoundError on 2.9.0.

Why does StreamReader on torchaudio 2.8 say Failed to intialize FFmpeg extension?

torchaudio 2.8.0 tried FFmpeg 6, 5 and 4 only; with FFmpeg 7 libraries it raised the same ImportError as with none. Use FFmpeg 6 or older, or move to torchcodec.

Written with AI assistance. Measured on 2026-10-24 on Linux with CPython 3.11.17, torch/torchaudio 2.8.0 (PyPI wheels) and 2.9.0 (CPU wheels), torchcodec 0.9.1, conda-forge FFmpeg 7. Output pasted unedited except shortened site-packages paths and cut tracebacks. PlainTables is our extension; torchaudio and torchcodec are free.