calesthio/OpenMontage · error · ValueError
face_choose must be a list of face choice objects
Error message
face_choose must be a list of face choice objects
What it means
ValueError from _normalize_face_choose when the face_choose input is neither a dict (auto-wrapped into a list) nor a list — e.g. a string like '1,2', an int, or None-like truthy garbage. The normalizer is lenient about shape (dict, list, string items) but requires a JSON-array-compatible value at the top.
Source
Thrown at tools/avatar/kling_lip_sync.py:397
}
self._copy_common_task_fields(inputs, payload)
return {
"protocol": "classic",
"path": "/v1/videos/advanced-lip-sync",
"payload": payload,
"operation": "advanced_lip_sync",
"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 []
View on GitHub (pinned to 95e1c3d0ab)
Solutions
- Pass a list: face_choose=[{'face_id': '1'}] or ['1'].
- A single dict is fine: face_choose={'face_id': '1'} — it is wrapped automatically.
- For a bare id string, use the face_id input, not face_choose.
Example fix
// before
result = tool.run({..., "face_choose": "1"})
// after
result = tool.run({..., "face_choose": ["1"]}) # or simply "face_id": "1" Defensive patterns
Strategy: type-guard
Validate before calling
raw = inputs.get("face_choose")
if isinstance(raw, str):
raw = [raw] # or reject and use face_id instead
if isinstance(raw, dict):
raw = [raw]
assert isinstance(raw, list), "face_choose must be a list" Type guard
def is_valid_face_choose(value: object) -> bool:
return isinstance(value, (list, dict)) Prevention
- Pass face_choose as a list (or single dict); pass bare id strings via face_id
- Validate shapes at the config/LLM boundary before they reach the tool
When it happens
Trigger: Passing face_choose='1' (bare string — use face_id instead), face_choose=1, or a comma-joined string of ids.
Common situations: Config/LLM front-ends serializing the selection as a delimited string; passing face_id value under the face_choose key.
Related errors
- advanced_lip_sync requires face_choose or face_id
- advanced_lip_sync currently supports exactly one face_choose
- face_choose items must include face_id
- Unsupported Kling lip-sync operation: {operation}
- Kling identify-face response missing data.session_id: {data}
AI-assisted analysis of calesthio/OpenMontage@95e1c3d0ab (2026-08-15).
Data as JSON: /api/errors/3b0873e2cbcb99d2.
Report an issue: GitHub.