{"record":{"id":"3970f1300465bb78","repo":"OpenBMB/VoxCPM","slug":"prompt-wav-path-and-prompt-text-must-both-be-provi","errorCode":null,"errorMessage":"prompt_wav_path and prompt_text must both be provided or both be None","messagePattern":"prompt_wav_path and prompt_text must both be provided or both be None","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"src/voxcpm/core.py","lineNumber":240,"sourceCode":"            seed: Optional random seed for reproducibility.\n        Returns:\n            Generator of numpy.ndarray: 1D waveform array (float32) on CPU.\n            Yields audio chunks for each generation step if ``streaming=True``,\n            otherwise yields a single array containing the final audio.\n        \"\"\"\n        if not isinstance(text, str) or not text.strip():\n            raise ValueError(\"target text must be a non-empty string\")\n\n        if prompt_wav_path is not None:\n            if not os.path.exists(prompt_wav_path):\n                raise FileNotFoundError(f\"prompt_wav_path does not exist: {prompt_wav_path}\")\n\n        if reference_wav_path is not None:\n            if not os.path.exists(reference_wav_path):\n                raise FileNotFoundError(f\"reference_wav_path does not exist: {reference_wav_path}\")\n\n        if (prompt_wav_path is None) != (prompt_text is None):\n            raise ValueError(\"prompt_wav_path and prompt_text must both be provided or both be None\")\n\n        is_v2 = isinstance(self.tts_model, VoxCPM2Model)\n        if reference_wav_path is not None and not is_v2:\n            raise ValueError(\"reference_wav_path is only supported with VoxCPM2 models\")\n\n        text = text.replace(\"\\n\", \" \")\n        text = re.sub(r\"\\s+\", \" \", text)\n        temp_files = []\n\n        try:\n            actual_prompt_path = prompt_wav_path\n            actual_ref_path = reference_wav_path\n\n            if denoise and self.denoiser is not None:\n                if prompt_wav_path is not None:\n                    with tempfile.NamedTemporaryFile(delete=False, suffix=\".wav\") as tmp:\n                        temp_files.append(tmp.name)\n                    self.denoiser.enhance(prompt_wav_path, output_path=temp_files[-1])","sourceCodeStart":222,"sourceCodeEnd":258,"githubUrl":"https://github.com/OpenBMB/VoxCPM/blob/f5a1c6a6b901bc732e20f0d59a369f6829ad717a/src/voxcpm/core.py#L222-L258","documentation":"_generate requires prompt_wav_path and prompt_text to be supplied together (both present or both None); supplying exactly one raises ValueError. The prompt text is needed to transcribe-align the prompt audio for voice cloning.","triggerScenarios":"generate(text, prompt_wav_path='a.wav') without prompt_text, or prompt_text='...' without prompt_wav_path.","commonSituations":"Assuming the library can transcribe the prompt automatically, or optional-arg handling code that passes prompt_text='' (not None) alongside no wav.","solutions":["Pass both prompt_wav_path and prompt_text together","Omit both for zero-shot synthesis without voice cloning","Ensure defaults are None, not empty strings, when building kwargs dynamically"],"exampleFix":"# before\nmodel.generate(text, prompt_wav_path=\"a.wav\")\n# after\nmodel.generate(text, prompt_wav_path=\"a.wav\", prompt_text=\"transcript of a.wav\")","handlingStrategy":"type-guard","validationCode":"if (prompt_wav_path is None) != (prompt_text is None):\n    raise ValueError(\"prompt_wav_path and prompt_text must be passed together\")","typeGuard":"def has_valid_prompt(wav, txt) -> bool:\n    return (wav is None) == (txt is None)","tryCatchPattern":null,"preventionTips":["Build a single prompt dict with both keys or neither","Default both to None in your wrapper signature"],"tags":["voice-cloning","parameter-validation","paired-arguments"],"backgroundTag":"missing-required-parameter","analyzedSha":"f5a1c6a6b901bc732e20f0d59a369f6829ad717a","analyzedAt":"2026-08-27T05:54:30.617Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}