{"record":{"id":"aefd09ffb9855368","repo":"calesthio/OpenMontage","slug":"cannot-select-face-without-face-id-id-face","errorCode":null,"errorMessage":"Cannot select face without face_id/id: {face}","messagePattern":"Cannot select face without face_id/id: (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"tools/avatar/kling_lip_sync.py","lineNumber":453,"sourceCode":"        if not inputs.get(\"auto_select_face\"):\n            return [], {\n                \"selection_method\": \"requires_user_selection\",\n                \"selection_reason\": \"Multiple faces detected and auto_select_face was not enabled\",\n                \"face_count\": len(faces),\n            }\n        selected = max(faces, key=self._face_area)\n        choice = [self._face_to_choice(selected)]\n        return choice, {\n            \"selection_method\": \"auto_selected\",\n            \"selection_reason\": \"auto_select_face=True selected the largest detected face area\",\n            \"selected_face\": choice,\n        }\n\n    @staticmethod\n    def _face_to_choice(face: dict[str, Any]) -> dict[str, Any]:\n        face_id = face.get(\"face_id\") or face.get(\"id\")\n        if not face_id:\n            raise ValueError(f\"Cannot select face without face_id/id: {face}\")\n        return {\"face_id\": str(face_id)}\n\n    @staticmethod\n    def _face_area(face: dict[str, Any]) -> float:\n        for key in (\"bbox\", \"box\"):\n            value = face.get(key)\n            if isinstance(value, list) and len(value) >= 4:\n                third = float(value[2])\n                fourth = float(value[3])\n                width_height_area = max(third, 0.0) * max(fourth, 0.0)\n                corner_width = third - float(value[0])\n                corner_height = fourth - float(value[1])\n                corner_area = (\n                    corner_width * corner_height\n                    if corner_width > 0 and corner_height > 0\n                    else 0.0\n                )\n                if corner_area and width_height_area:","sourceCodeStart":435,"sourceCodeEnd":471,"githubUrl":"https://github.com/calesthio/OpenMontage/blob/95e1c3d0ab93482159818560f6a8c8e866b9139f/tools/avatar/kling_lip_sync.py#L435-L471","documentation":"Raised by KlingLipSyncTool._face_to_choice when the tool tries to convert a face record from identify_face into a selection choice but the record has neither face_id nor id. This happens on the automatic paths: exactly one detected face, or auto_select_face=True picking the largest face. The tool cannot tell Kling which face to animate without an identifier.","triggerScenarios":"Running kling_lip_sync on a video where identify_face returns face records whose id field is named something else (e.g. \"faceid\", \"uuid\") or is missing entirely. Triggered either via the single-face shortcut or via auto_select_face=True with multiple faces.","commonSituations":"A changed or unexpected identify_face response schema (upstream API version change), or a hand-crafted faces list passed in tests/mocks that omits the id key.","solutions":["Inspect the identify_face output for your video and pass explicit face_choose entries using whatever id field it actually returns, if any","Re-run identify_face; if its schema truly lacks ids, this is a tool bug — report it with the raw face payload","If mocking in tests, include face_id (or id) in every face record"],"exampleFix":"# before (mock faces without ids)\nfaces = [{\"bbox\": [10, 10, 100, 100]}]\n\n# after\nfaces = [{\"face_id\": \"face_1\", \"bbox\": [10, 10, 100, 100]}]","handlingStrategy":"validation","validationCode":"faces = identify_face(video_id=vid)[\"faces\"]\nif not all(f.get(\"face_id\") or f.get(\"id\") for f in faces):\n    raise ValueError(f\"identify_face returned id-less records: {faces}\")\n# safe to proceed with auto_select_face or single-face shortcut","typeGuard":"def faces_have_ids(faces) -> bool:\n    return all(bool(f.get(\"face_id\") or f.get(\"id\")) for f in faces)","tryCatchPattern":null,"preventionTips":["Run identify_face first and assert every record carries face_id/id","Pass explicit face_choose ids instead of relying on auto-selection when detection output looks unusual","Report id-less detection payloads as a schema issue"],"tags":["kling","lip-sync","face-detection","schema"],"backgroundTag":null,"analyzedSha":"95e1c3d0ab93482159818560f6a8c8e866b9139f","analyzedAt":"2026-08-15T06:31:20.014Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}