Comfy-Org/ComfyUI · error · ValueError

Expected waveform tensor shape (1, channels, samples)

Error message

Expected waveform tensor shape (1, channels, samples)

What it means

audio_tensor_to_contiguous_ndarray requires the Comfy AUDIO waveform tensor to be exactly 3-D with a batch dimension of 1, i.e. shape (1, channels, samples). It raises ValueError when waveform.ndim != 3 or waveform.shape[0] != 1 because the PyAV encoding path squeezes dimension 0 and cannot handle a batched or rank-mismatched tensor.

Source

Thrown at comfy_api_nodes/util/conversions.py:275

    audio_bytes_io.seek(0)
    return audio_bytes_io


def audio_tensor_to_contiguous_ndarray(waveform: torch.Tensor) -> np.ndarray:
    """
    Prepares audio waveform for av library by converting to a contiguous numpy array.

    Args:
        waveform: a tensor of shape (1, channels, samples) derived from a Comfy `AUDIO` type.

    Returns:
        Contiguous numpy array of the audio waveform.

    Raises:
        ValueError: If the waveform is not shaped (1, channels, samples).
    """
    if waveform.ndim != 3 or waveform.shape[0] != 1:
        raise ValueError("Expected waveform tensor shape (1, channels, samples)")

    # Prepare for av: remove batch dim, move to CPU, make contiguous, convert to numpy array
    audio_data_np = waveform.squeeze(0).cpu().contiguous().numpy()
    if audio_data_np.dtype != np.float32:
        audio_data_np = audio_data_np.astype(np.float32)

    return audio_data_np


def audio_input_to_mp3(audio: Input.Audio) -> BytesIO:
    audio_data_np = audio_tensor_to_contiguous_ndarray(audio["waveform"])
    sample_rate = int(audio["sample_rate"])

    output_buffer = BytesIO()
    output_container = av.open(output_buffer, mode="w", format="mp3")

    out_stream = output_container.add_stream("libmp3lame", rate=sample_rate)
    out_stream.bit_rate = 320000

View on GitHub (pinned to 1c6d8d45b3)

Solutions

  1. Inspect waveform.shape before the call and fix the upstream node producing the AUDIO dict.
  2. If the tensor is (C, T), add a batch dimension: waveform.unsqueeze(0).
  3. If you have a batch (N, C, T), select one item with waveform[i:i+1] or loop over items.
  4. Prefer sourcing AUDIO from Comfy's standard audio nodes so the (1, C, T) contract holds.

Example fix

// before
mp3 = audio_input_to_mp3(audio)  # audio['waveform'] is (C, T)

// after
waveform = audio['waveform']
if waveform.ndim == 2:
    waveform = waveform.unsqueeze(0)
audio = {**audio, 'waveform': waveform}
mp3 = audio_input_to_mp3(audio)
Defensive patterns

Strategy: validation

Validate before calling

def is_valid_audio_waveform(waveform: torch.Tensor) -> bool:
    return waveform.ndim == 3 and waveform.shape[0] == 1

Type guard

from typing import TypeGuard

def is_comfy_audio(audio: dict) -> TypeGuard[dict]:
    wf = audio.get('waveform')
    return (
        isinstance(wf, torch.Tensor)
        and wf.ndim == 3
        and wf.shape[0] == 1
        and isinstance(audio.get('sample_rate'), int)
    )

Prevention

When it happens

Trigger: Passing an AUDIO dict whose waveform is (channels, samples) (2-D), (N, channels, samples) with N>1 (a batch), or a raw unbatched tensor into audio_input_to_mp3 or the av-based video/audio conversion helpers in comfy_api_nodes/util/conversions.py.

Common situations: Manually constructing the AUDIO dict instead of using a Load Audio / audio preview node; batching audio through a node that assumes a single clip; feeding a latent-shaped or preprocessed tensor by mistake.

Related errors


AI-assisted analysis of Comfy-Org/ComfyUI@1c6d8d45b3 (2026-08-14). Data as JSON: /api/errors/3912047ac2f86456. Report an issue: GitHub.