{"record":{"id":"34ee02f837c8c0fb","repo":"microsoft/VibeVoice","slug":"no-valid-speaker-lines-found-in-script","errorCode":null,"errorMessage":"No valid speaker lines found in script","messagePattern":"No valid speaker lines found in script","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"vibevoice/processor/vibevoice_processor.py","lineNumber":619,"sourceCode":"                \n        # First pass: parse all lines and collect speaker IDs\n        for line in lines:\n            if not line.strip():\n                continue\n                \n            # Use regex to handle edge cases like multiple colons\n            match = re.match(r'^Speaker\\s+(\\d+)\\s*:\\s*(.*)$', line.strip(), re.IGNORECASE)\n            \n            if match:\n                speaker_id = int(match.group(1))\n                text = ' ' + match.group(2).strip()\n                parsed_lines.append((speaker_id, text))\n                speaker_ids.append(speaker_id)\n            else:\n                logger.warning(f\"Could not parse line: '{line}'\")\n        \n        if not parsed_lines:\n            raise ValueError(\"No valid speaker lines found in script\")\n        \n        # Check if we need to normalize speaker IDs (only if all are > 0)\n        min_speaker_id = min(speaker_ids)\n        if min_speaker_id > 0:\n            # Normalize to start from 0\n            normalized_lines = []\n            for speaker_id, text in parsed_lines:\n                normalized_lines.append((speaker_id - 1, text))\n            return normalized_lines\n        else:\n            # Keep original IDs\n            return parsed_lines\n\n    def _merge_inputs(self, text_inputs: BatchEncoding, audio_inputs: Dict) -> BatchEncoding:\n        \"\"\"Merge text and audio inputs into a single BatchEncoding.\"\"\"\n        # Start with text inputs\n        merged = BatchEncoding(text_inputs)\n        ","sourceCodeStart":601,"sourceCodeEnd":637,"githubUrl":"https://github.com/microsoft/VibeVoice/blob/94da20d98b2fa7688e9cbfaf7692ddb4954f7600/vibevoice/processor/vibevoice_processor.py#L601-L637","documentation":"The internal script format requires every dialogue line to match '^Speaker <digits>: <text>' (case-insensitive). _parse_script scans the script and keeps only matched lines; if none match — every line fell into the 'Could not parse line' warning branch — this ValueError is raised. This guards against downstream index errors on empty speaker lists.","triggerScenarios":"Passing a script string in a different dialogue format: 'Alice: hi', '[1]: hi', '1: hi' (missing the literal word 'Speaker'), or a raw paragraph with no speaker prefixes at all.","commonSituations":"Users passing free-form narration text expecting single-speaker TTS; scripts exported with speaker labels like 'S1:' or character names; localizing the word 'Speaker' into another language.","solutions":["Format the input as 'Speaker 1: <text>' lines, one utterance per line (any integer speaker ids work).","For single-speaker plain text, wrap it programmatically: '\\n'.join(f'Speaker 1: {line}' for line in text.splitlines() if line.strip()).","Check preceding logger.warning lines to see exactly which lines failed to parse."],"exampleFix":"# before\nprocessor(text='Alice: hello there')\n\n# after\nprocessor(text='Speaker 1: hello there')","handlingStrategy":"validation","validationCode":"import re\nSPEAKER_RE = re.compile(r'^Speaker\\s+\\d+\\s*:', re.IGNORECASE)\nif not any(SPEAKER_RE.match(l) for l in script.splitlines() if l.strip()):\n    script = '\\n'.join(f'Speaker 1: {l}' for l in script.splitlines() if l.strip())","typeGuard":"def has_speaker_lines(script: str) -> bool:\n    import re\n    return any(re.match(r'^Speaker\\s+\\d+\\s*:', l.strip(), re.I)\n               for l in script.splitlines() if l.strip())","tryCatchPattern":"try:\n    enc = processor(text=script)\nexcept ValueError as e:\n    if 'No valid speaker lines' in str(e):\n        wrapped = '\\n'.join(f'Speaker 1: {l}' for l in script.splitlines() if l.strip())\n        enc = processor(text=wrapped)\n    else:\n        raise","preventionTips":["Always author scripts as 'Speaker N: text' lines; the word 'Speaker' is mandatory.","Auto-wrap single-speaker plain text into Speaker 1 lines before calling.","Scan for the warning logs listing unparseable lines to fix formatting early."],"tags":["script","parsing","input-format","tts"],"backgroundTag":null,"analyzedSha":"94da20d98b2fa7688e9cbfaf7692ddb4954f7600","analyzedAt":"2026-08-15T04:12:07.418Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}