Skip to content

SymphoniaDecoder::new() panics on SeekError during initialization with M4A files #846

@Cloud370

Description

@Cloud370

Summary

SymphoniaDecoder::new() panics via unreachable!() when symphonia's FormatReader::next_packet() returns Error::SeekError during initialization. This consistently occurs with M4A (AAC in ISO MP4 container) files.

Affected codesrc/decoder/symphonia.rs line 40 (master):

Error::SeekError(_) => {
    unreachable!("Seek errors should not occur during initialization")
}

Steps to Reproduce

  1. Obtain an M4A audio file (AAC in ISO MP4 container, e.g. NetEase Cloud Music "exhigh" quality)
  2. Load the file bytes into memory
  3. Attempt to decode with any rodio decoder method:
use rodio::Decoder;
use std::io::Cursor;

let audio_bytes: Vec<u8> = std::fs::read("song.m4a").unwrap();
// This panics:
let decoder = Decoder::new(Cursor::new(audio_bytes));

The M4A file has a standard ftyp box header: 00 00 00 1c 66 74 79 70 4d 34 41 20 (ftyp + brand M4A ).

Observed Behavior

The program panics with:

thread 'audio' panicked at 'internal error: entered unreachable code: Seek errors should not occur during initialization'

All decoder methods are affected (Decoder::new, Decoder::new_mp3, Decoder::new_flac, Decoder::new_aac, Decoder::new_wav, Decoder::new_vorbis) — they all go through SymphoniaDecoder::init() which calls format.next_packet(), and symphonia's ISO MP4 format reader returns Error::SeekError for these files.

Expected Behavior

Decoder::new() should return Err(DecoderError::...) instead of panicking. A library should never panic on valid user input.

Root Cause

SymphoniaDecoder::init() reads packets in a loop via format.next_packet(). The error handling at the call site (SymphoniaDecoder::new()) assumes SeekError can never be returned during initialization, but symphonia's ISO MP4 FormatReader can return Error::SeekError from next_packet() for certain M4A files.

Suggested Fix

Replace the unreachable!() with a proper error return:

// Before:
Error::SeekError(_) => {
    unreachable!("Seek errors should not occur during initialization")
}

// After:
Error::SeekError(e) => Err(DecoderError::IoError(format!("seek error during init: {}", e))),

This is a one-line fix. A new DecoderError variant (e.g. SeekError) would be even cleaner but would be a breaking change.

Versions

  • rodio: 0.20.1 (also verified on master — the unreachable!() is still present at line 40)
  • symphonia: 0.5.5
  • OS: Windows 11
  • Rust: stable

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions