{"record":{"id":"8f9837ff3502b7c4","repo":"calesthio/OpenMontage","slug":"advanced-lip-sync-currently-supports-exactly-one-f","errorCode":null,"errorMessage":"advanced_lip_sync currently supports exactly one face_choose item","messagePattern":"advanced_lip_sync currently supports exactly one face_choose item","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"tools/avatar/kling_lip_sync.py","lineNumber":372,"sourceCode":"        if inputs.get(\"video_url\"):\n            payload[\"video_url\"] = str(inputs[\"video_url\"])\n        if not payload:\n            raise ValueError(\"Kling identify_face requires video_id or video_url\")\n        return {\n            \"path\": \"/v1/videos/identify-face\",\n            \"payload\": payload,\n            \"operation\": \"identify_face\",\n        }\n\n    def _build_advanced_request(self, inputs: dict[str, Any]) -> dict[str, Any]:\n        session_id = str(inputs.get(\"session_id\") or \"\").strip()\n        if not session_id:\n            raise ValueError(\"advanced_lip_sync requires session_id\")\n        face_choose = self._normalize_face_choose(inputs)\n        if not face_choose:\n            raise ValueError(\"advanced_lip_sync requires face_choose or face_id\")\n        if len(face_choose) != 1:\n            raise ValueError(\"advanced_lip_sync currently supports exactly one face_choose item\")\n        face_item = face_choose[0]\n        audio_source = self._copy_audio_input(inputs, face_item)\n        self._copy_timing_fields(inputs, face_item)\n        payload: dict[str, Any] = {\n            \"session_id\": session_id,\n            \"face_choose\": face_choose,\n        }\n        self._copy_common_task_fields(inputs, payload)\n        return {\n            \"protocol\": \"classic\",\n            \"path\": \"/v1/videos/advanced-lip-sync\",\n            \"payload\": payload,\n            \"operation\": \"advanced_lip_sync\",\n            \"model\": \"kling-official-lip-sync\",\n            \"audio_source\": audio_source,\n        }\n\n    @staticmethod","sourceCodeStart":354,"sourceCodeEnd":390,"githubUrl":"https://github.com/calesthio/OpenMontage/blob/95e1c3d0ab93482159818560f6a8c8e866b9139f/tools/avatar/kling_lip_sync.py#L354-L390","documentation":"ValueError from _build_advanced_request when the normalized face_choose list has zero or more than one entries. The underlying Kling advanced-lip-sync binding in this client handles exactly one face per call; multi-face or empty selections are rejected before the request is sent.","triggerScenarios":"Passing face_choose with 2+ items (multi-person video) to one advanced_lip_sync call; passing an empty list explicitly.","commonSituations":"Identify found several faces and the caller forwards all of them; attempting batch animation in a single request.","solutions":["Pick one face per call: pass a single-item face_choose or a bare face_id.","To animate multiple faces, run one advanced_lip_sync call per face (with the same session_id) and merge outputs afterwards.","Empty list means the selection step failed — re-read the identify result and choose a face."],"exampleFix":"// before\nresult = tool.run({..., \"face_choose\": [{\"face_id\": \"1\"}, {\"face_id\": \"2\"}]})\n\n// after\nr1 = tool.run({..., \"face_choose\": [{\"face_id\": \"1\"}]})\nr2 = tool.run({..., \"face_choose\": [{\"face_id\": \"2\"}]})","handlingStrategy":"validation","validationCode":"face_choose = inputs.get(\"face_choose\") or ([{\"face_id\": str(inputs[\"face_id\"])}] if inputs.get(\"face_id\") else [])\nassert len(face_choose) == 1, \"one face per advanced_lip_sync call\"","typeGuard":"def is_single_face_selection(face_choose: list) -> bool:\n    return len(face_choose) == 1","tryCatchPattern":null,"preventionTips":["Loop one call per face instead of batching multiple faces into one request","Treat an empty selection as a bug in the upstream selection step"],"tags":["kling","lip-sync","face-selection","cardinality"],"backgroundTag":null,"analyzedSha":"95e1c3d0ab93482159818560f6a8c8e866b9139f","analyzedAt":"2026-08-15T06:31:20.014Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}