calesthio/OpenMontage · error · ValueError

advanced_lip_sync requires sound_end_time

Error message

advanced_lip_sync requires sound_end_time

What it means

Raised by KlingLipSyncTool._copy_timing_fields on the advanced lip-sync path when sound_end_time is absent from both the top-level inputs and face_choose[0]. Unlike full lip-sync (which infers it, see error 143), the advanced path requires an explicit crop end — there is no inference.

Source

Thrown at tools/avatar/kling_lip_sync.py:560

                )
            value = nested if nested is not None else top_level
            if value is None:
                value = default
            face_item[key] = int(value)

        nested_end = face_item.get("sound_end_time")
        top_level_end = inputs.get("sound_end_time")
        if (
            nested_end is not None
            and top_level_end is not None
            and int(nested_end) != int(top_level_end)
        ):
            raise ValueError(
                "Conflicting sound_end_time values between top-level input and face_choose[0]"
            )
        sound_end = nested_end if nested_end is not None else top_level_end
        if sound_end is None:
            raise ValueError("advanced_lip_sync requires sound_end_time")
        face_item["sound_end_time"] = int(sound_end)
        if face_item["sound_end_time"] - face_item["sound_start_time"] < 2000:
            raise ValueError("advanced_lip_sync requires at least 2000ms of cropped audio")

        for key in ("sound_volume", "original_audio_volume"):
            nested = face_item.get(key)
            top_level = inputs.get(key)
            if nested is not None and top_level is not None and float(nested) != float(top_level):
                raise ValueError(
                    f"Conflicting {key} values between top-level input and face_choose[0]"
                )
            value = nested if nested is not None else top_level
            if value is not None:
                face_item[key] = float(value)

    @staticmethod
    def _face_choose_result_metadata(
        face_choose: list[dict[str, Any]],

View on GitHub (pinned to 95e1c3d0ab)

Solutions

  1. Add sound_end_time (ms) to the top-level inputs or to face_choose[0]
  2. If you intended automatic inference, use full_lip_sync instead of advanced_lip_sync
  3. Remember the value must be at least sound_start_time + 2000 (see error 147)

Example fix

# before
inputs = {"video_id": vid, "face_choose": [{"face_id": "f1"}], "lip_sync_mode": "advanced"}

# after
inputs = {"video_id": vid, "face_choose": [{"face_id": "f1", "sound_end_time": 6000}], "lip_sync_mode": "advanced"}
Defensive patterns

Strategy: validation

Validate before calling

if mode == "advanced":
    face_item = (inputs.get("face_choose") or [{}])[0]
    if inputs.get("sound_end_time") is None and face_item.get("sound_end_time") is None:
        raise ValueError("advanced_lip_sync needs explicit sound_end_time")

Prevention

When it happens

Trigger: Calling advanced_lip_sync (multi-face / per-face timing mode) with only sound_insert_time or a bare face_choose list of face ids and no sound_end_time anywhere.

Common situations: Switching a payload from full_lip_sync to advanced_lip_sync and assuming the same inference applies; passing only face ids as strings (which carry no timing) into face_choose.

Related errors


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