microsoft/VibeVoice · error · ValueError

JSON file must contain a list of speaker entries

Error message

JSON file must contain a list of speaker entries

What it means

When `text` points at a .json file, the processor expects a top-level JSON array of {'speaker': ..., 'text': ...} entries. If json.load succeeds but yields an object (dict), a string, a number, or null, this ValueError is raised — the file parsed fine but has the wrong shape.

Source

Thrown at vibevoice/processor/vibevoice_processor.py:526

            
        return result
        
    def _convert_json_to_script(self, json_file: str) -> str:
        """
        Convert JSON format to script format.
        Expected JSON format:
        [
            {"speaker": "1", "text": "Hello everyone..."},
            {"speaker": "2", "text": "Great to be here..."}
        ]
        """
        import json
        
        with open(json_file, 'r', encoding='utf-8') as f:
            data = json.load(f)
        
        if not isinstance(data, list):
            raise ValueError("JSON file must contain a list of speaker entries")
        
        script_lines = []
        for item in data:
            if not isinstance(item, dict):
                logger.warning(f"Skipping non-dict entry: {item}")
                continue
                
            speaker = item.get('speaker')
            text = item.get('text')
            
            if speaker is None or text is None:
                logger.warning(f"Skipping entry missing speaker or text: {item}")
                continue
            
            # Ensure speaker ID is valid
            try:
                speaker_id = int(speaker)
            except (ValueError, TypeError):

View on GitHub (pinned to 94da20d98b)

Solutions

  1. Rewrite the JSON to a top-level list: [{"speaker": "1", "text": "..."}, {"speaker": "2", "text": "..."}].
  2. If your file wraps entries under a key (e.g. 'segments'), extract that array into a new file or pass the inner list via a temp file.
  3. Convert JSON-lines exports to a single JSON array before feeding them in.

Example fix

// before: dialog.json
{"segments": [{"speaker": "1", "text": "Hi"}]}

// after: dialog.json
[{"speaker": "1", "text": "Hi"}]
Defensive patterns

Strategy: validation

Validate before calling

import json
data = json.load(open(path))
if not isinstance(data, list):
    for key in ('segments', 'utterances', 'data'):  # common wrappers
        if isinstance(data, dict) and isinstance(data.get(key), list):
            data = data[key]; break
    else:
        raise ValueError('transcript JSON root must be a list of speaker entries')

Type guard

def is_speaker_entry_list(data) -> bool:
    return isinstance(data, list) and all(
        isinstance(x, dict) and 'speaker' in x and 'text' in x for x in data)

Try / catch

try:
    enc = processor(text=json_path)
except ValueError as e:
    if 'must contain a list' in str(e):
        data = json.load(open(json_path))['segments']  # unwrap known container
        json.dump(data, open(json_path, 'w'))
        enc = processor(text=json_path)
    else:
        raise

Prevention

When it happens

Trigger: Passing a .json file whose root is a dict — e.g. {"segments": [...]} or a bare {'speaker': '1', 'text': 'hi'} entry instead of a list wrapping it; or a JSON-lines file (one object per line) which json.load reads as whatever the first scalar parses to.

Common situations: Datasets that wrap transcripts in a metadata object ({'utterances': [...]}); annotation tools exporting a single-session dict; users hand-editing the example format and dropping the outer brackets.

Related errors


AI-assisted analysis of microsoft/VibeVoice@94da20d98b (2026-08-15). Data as JSON: /api/errors/c6e431e53f31e71e. Report an issue: GitHub.