calesthio/OpenMontage · error · ValueError

Conflicting {key} values between top-level input and face_ch

Error message

Conflicting {key} values between top-level input and face_choose[0]

What it means

Raised by KlingLipSyncTool._copy_timing_fields when sound_start_time or sound_insert_time is set both at the top level of the inputs and inside face_choose[0], and the two values differ after int() coercion. The tool refuses to guess which value wins, so it fails fast rather than silently picking one.

Source

Thrown at tools/avatar/kling_lip_sync.py:540

    def _local_audio_duration_ms(inputs: dict[str, Any]) -> int | None:
        sound_path = inputs.get("sound_file_path") or inputs.get("audio_path")
        if not sound_path:
            return None
        path = Path(sound_path)
        if not path.is_file():
            return None
        seconds = probe_output(path).get("duration_seconds")
        if not seconds:
            return None
        return int(round(float(seconds) * 1000))

    @staticmethod
    def _copy_timing_fields(inputs: dict[str, Any], face_item: dict[str, Any]) -> None:
        for key, default in (("sound_start_time", 0), ("sound_insert_time", 0)):
            nested = face_item.get(key)
            top_level = inputs.get(key)
            if nested is not None and top_level is not None and int(nested) != int(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 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

View on GitHub (pinned to 95e1c3d0ab)

Solutions

  1. Keep timing values in exactly one place: either top-level or face_choose[0], not both
  2. If both must exist, make them equal so the conflict check passes
  3. Prefer per-face values in face_choose when syncing multiple faces, and delete the top-level keys

Example fix

# before
inputs = {"sound_insert_time": 1000, "face_choose": [{"face_id": "f1", "sound_insert_time": 2000}]}

# after
inputs = {"face_choose": [{"face_id": "f1", "sound_insert_time": 2000}]}
Defensive patterns

Strategy: validation

Validate before calling

face_item = (inputs.get("face_choose") or [{}])[0]
for key in ("sound_start_time", "sound_insert_time"):
    nested, top = face_item.get(key), inputs.get(key)
    if nested is not None and top is not None and int(nested) != int(top):
        raise ValueError(f"conflicting {key}: pick one scope")

Prevention

When it happens

Trigger: advanced_lip_sync with e.g. inputs['sound_insert_time']=1000 plus face_choose=[{'face_id': 'f1', 'sound_insert_time': 2000}] — 1000 != 2000 raises. Note the error names the concrete key (sound_start_time or sound_insert_time) in {key}.

Common situations: Copying a working top-level payload and later adding per-face overrides without removing the top-level copy; agent pipelines merging user settings with template defaults at both levels.

Related errors


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