hiyouga/LlamaFactory · error · ValueError
Each {VIDEO_PLACEHOLDER} must be followed by an {AUDIO_PLACE
Error message
Each {VIDEO_PLACEHOLDER} must be followed by an {AUDIO_PLACEHOLDER} when using audio in video. What it means
With use_audio_in_video enabled, the Qwen2-Omni plugin requires each <video> placeholder in the message content to be followed (later in the string) by an <audio> placeholder, because it substitutes the video and its audio track as one fused token block with aligned timestamps.
Source
Thrown at src/llamafactory/data/mm_plugin.py:3028
IMAGE_PLACEHOLDER,
f"{self.vision_bos_token}{self.image_token * image_seqlen}{self.vision_eos_token}",
1,
)
num_image_tokens += 1
if (
use_audio_in_video and len(audios) and len(videos)
): # if use the audio of video # deal video token and audio token together
if len(videos) != len(audios):
raise ValueError(
f"Number of videos ({len(videos)}) must match number of audios ({len(audios)}) when using audio in video."
)
while VIDEO_PLACEHOLDER in content:
video_pos = content.find(VIDEO_PLACEHOLDER)
audio_pos = content.find(AUDIO_PLACEHOLDER, video_pos)
if audio_pos == -1 or audio_pos < video_pos:
raise ValueError(
f"Each {VIDEO_PLACEHOLDER} must be followed by an {AUDIO_PLACEHOLDER} when using audio in video."
)
position_id_per_seconds: int = getattr(processor, "position_id_per_seconds", 25)
audio_t_index = torch.arange(audio_lengths[num_audio_tokens])
video_t_index = (
torch.arange(video_grid_thw[num_video_tokens][0])
.view(-1, 1, 1)
.expand(
-1,
video_grid_thw[num_video_tokens][1] // image_processor.merge_size,
video_grid_thw[num_video_tokens][2] // image_processor.merge_size,
)
.flatten()
* mm_inputs["video_second_per_grid"][num_video_tokens]
* position_id_per_seconds
).long()
t_ntoken_per_chunk = position_id_per_seconds * 2View on GitHub (pinned to f28afaf635)
Solutions
- Rewrite the content so every <video> is immediately followed by its <audio>: e.g. 'Describe <video><audio>'.
- Ensure placeholder ordering is video-then-audio in every turn that uses audio-in-video.
- If audio is separate from the video (not the video's soundtrack), disable use_audio_in_video.
Example fix
// before "content": "What is said in <audio> and shown in <video>?" // after "content": "What is shown and said in <video><audio>?"
Defensive patterns
Strategy: validation
Validate before calling
def audio_in_video_ok(content):
v = content.find('<video>')
while v != -1:
a = content.find('<audio>', v)
if a == -1:
return False
v = content.find('<video>', a)
return True
assert audio_in_video_ok(content) Prevention
- Standardize the fused placeholder pattern '<video><audio>' in every audio-in-video prompt.
- Never reorder placeholders manually; build prompts from a template function.
When it happens
Trigger: A sample whose content contains <video> but the next <audio> placeholder is missing entirely (content.find returns -1) — e.g. only <video> in the prompt while audios list is non-empty, or audio placeholder placed before the video.
Common situations: Reordering placeholders in the prompt template; writing '<audio> then <video>' instead of '<video> then <audio>'; forgetting the <audio> tag when adding an audio column.
Related errors
- Number of videos ({len(videos)}) must match number of audios
- This model does not support video input. Please check whethe
- This model does not support audio input. Please check whethe
- Audio feature extractor was not found, please check and upda
- The number of videos does not match the number of {VIDEO_PLA
AI-assisted analysis of hiyouga/LlamaFactory@f28afaf635 (2026-08-14).
Data as JSON: /api/errors/27b00b7cf7486c7b.
Report an issue: GitHub.