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

  1. Pass a list: face_choose=[{'face_id': '1'}] or ['1'].
  2. A single dict is fine: face_choose={'face_id': '1'} — it is wrapped automatically.
  3. 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

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


AI-assisted analysis of calesthio/OpenMontage@95e1c3d0ab (2026-08-15). Data as JSON: /api/errors/3b0873e2cbcb99d2. Report an issue: GitHub.