calesthio/OpenMontage · error · ValueError
face_choose items must include face_id
Error message
face_choose items must include face_id
What it means
ValueError from _normalize_face_choose when a dict item in the face_choose list carries neither face_id nor id. String items are converted to {'face_id': item} automatically, but object items must identify the face themselves — the normalizer even maps legacy 'id' to 'face_id', so an item missing both has nothing to bind the choice to.
Source
Thrown at tools/avatar/kling_lip_sync.py:404
"model": "kling-official-lip-sync",
"audio_source": audio_source,
}
@staticmethod
def _normalize_face_choose(inputs: dict[str, Any]) -> list[dict[str, Any]]:
if inputs.get("face_choose"):
raw = inputs["face_choose"]
if isinstance(raw, dict):
raw = [raw]
if not isinstance(raw, list):
raise ValueError("face_choose must be a list of face choice objects")
normalized: list[dict[str, Any]] = []
for item in raw:
if isinstance(item, str):
normalized.append({"face_id": item})
elif isinstance(item, dict):
if not (item.get("face_id") or item.get("id")):
raise ValueError("face_choose items must include face_id")
record = dict(item)
if "face_id" not in record and record.get("id"):
record["face_id"] = record.pop("id")
normalized.append(record)
else:
raise ValueError("face_choose items must be strings or objects")
return normalized
if inputs.get("face_id"):
return [{"face_id": str(inputs["face_id"])}]
return []
def _face_selection(
self,
faces: list[dict[str, Any]],
inputs: dict[str, Any],
) -> tuple[list[dict[str, Any]], dict[str, Any]]:
explicit = self._normalize_face_choose(inputs)
if explicit:View on GitHub (pinned to 95e1c3d0ab)
Solutions
- Add the identifier: {'face_id': '1', ...} — use the face_id values from the identify_face result.
- If the source records use 'id', that is accepted too and normalized automatically.
- Bare strings in the list also work: ['1'].
Example fix
// before
result = tool.run({..., "face_choose": [{"face_index": 0, "lb": 1.0}]})
// after
result = tool.run({..., "face_choose": [{"face_id": "1", "face_index": 0, "lb": 1.0}]}) Defensive patterns
Strategy: validation
Validate before calling
for item in face_choose:
if isinstance(item, dict):
assert item.get("face_id") or item.get("id"), \
f"face_choose item missing face_id: {item}" Type guard
def item_has_face_id(item: dict) -> bool:
return bool(item.get("face_id") or item.get("id")) Prevention
- Copy face_id values verbatim from the identify_face result
- Remember 'id' is accepted and normalized to 'face_id'; other keys alone are not
When it happens
Trigger: Passing face_choose=[{'face_index': 0}] or [{...timing fields...}] with the identifier omitted; forwarding raw identify-face entries whose id lives under yet another key.
Common situations: Developer copies a face record from the identify artifact but the id field name differs (e.g. 'faceID' or 'index'); LLM-generated face_choose omitting the id.
Related errors
- advanced_lip_sync requires face_choose or face_id
- Kling identify_face requires video_id or video_url
- advanced_lip_sync requires session_id
- advanced_lip_sync currently supports exactly one face_choose
- face_choose must be a list of face choice objects
AI-assisted analysis of calesthio/OpenMontage@95e1c3d0ab (2026-08-15).
Data as JSON: /api/errors/605a937633163cca.
Report an issue: GitHub.