Comfy-Org/ComfyUI · error · ValueError
AudioJoin: Both input audios must be mono.
Error message
AudioJoin: Both input audios must be mono.
What it means
JoinAudioChannels stacks two mono signals into stereo by slicing channel dim 1; it hard-requires both inputs to have exactly 1 channel. Either input being stereo or multichannel raises before sample-rate matching runs.
Source
Thrown at comfy_extras/nodes_audio.py:550
IO.Audio.Output(display_name="audio"),
],
)
@classmethod
def execute(cls, audio_left, audio_right) -> IO.NodeOutput:
if audio_left is None and audio_right is None:
return IO.NodeOutput(None)
if audio_left is None:
return IO.NodeOutput(audio_right)
if audio_right is None:
return IO.NodeOutput(audio_left)
waveform_left = audio_left["waveform"]
sample_rate_left = audio_left["sample_rate"]
waveform_right = audio_right["waveform"]
sample_rate_right = audio_right["sample_rate"]
if waveform_left.shape[1] != 1 or waveform_right.shape[1] != 1:
raise ValueError("AudioJoin: Both input audios must be mono.")
# Handle different sample rates by resampling to the higher rate
waveform_left, waveform_right, output_sample_rate = match_audio_sample_rates(
waveform_left, sample_rate_left, waveform_right, sample_rate_right
)
# Handle different lengths by trimming to the shorter length
length_left = waveform_left.shape[-1]
length_right = waveform_right.shape[-1]
if length_left != length_right:
min_length = min(length_left, length_right)
if length_left > min_length:
logging.info(f"JoinAudioChannels: Trimming left channel from {length_left} to {min_length} samples.")
waveform_left = waveform_left[..., :min_length]
if length_right > min_length:
logging.info(f"JoinAudioChannels: Trimming right channel from {length_right} to {min_length} samples.")
waveform_right = waveform_right[..., :min_length]View on GitHub (pinned to 1c6d8d45b3)
Solutions
- Downmix or select a single channel per input first: wav[:, :1, :] or mean over dim 1
- Use SplitAudioChannels to extract a mono channel from a stereo input before joining
- Re-export sources as mono where a mono-to-stereo placement is intended
- Assert both shapes are (B, 1, N) upstream so the failure is caught at the boundary
Example fix
// before
stereo = JoinAudioChannels(music_stereo, voice_mono) # raises
// after
music_mono = {'waveform': music_stereo['waveform'][:, :1, :], 'sample_rate': music_stereo['sample_rate']}
stereo = JoinAudioChannels(music_mono, voice_mono) Defensive patterns
Strategy: type-guard
Validate before calling
def to_mono(audio):
wf = audio['waveform']
if wf.shape[1] > 1:
wf = wf[:, :1, :] # or wf.mean(dim=1, keepdim=True)
return {'waveform': wf, 'sample_rate': audio['sample_rate']} Type guard
def is_mono(audio) -> bool:
return audio is not None and audio['waveform'].shape[1] == 1 Prevention
- Extract a single channel per input before joining
- Assert (batch, 1, samples) shape at your adapter boundary
- Use SplitAudioChannels to demux stereo before JoinAudioChannels
When it happens
Trigger: Passing a stereo file's audio as audio_left/audio_right; passing 4/6-channel surround audio; upstream nodes that output batched multi-channel tensors where dim 1 > 1.
Common situations: Mixing audio from heterogeneous sources (one mono mic, one stereo music bed) into a stereo join; re-using a join template after the source export changed to stereo.
Related errors
- AudioSplit: Input audio must be stereo (2 channels), got {wa
- ERROR: audio encoder file is invalid or unsupported embed_di
- ERROR: audio encoder not supported.
- Image-token count {image_idx.shape[0]} != ViT output count {
- attention_mask must be {expected}, got {tuple(attention_mask
AI-assisted analysis of Comfy-Org/ComfyUI@1c6d8d45b3 (2026-08-14).
Data as JSON: /api/errors/9465979c19bac4b6.
Report an issue: GitHub.