calesthio/OpenMontage · error · ValueError

Conflicting audio input between top-level fields and face_ch

Error message

Conflicting audio input between top-level fields and face_choose[0]

What it means

Raised by KlingLipSyncTool._copy_audio_input when face_choose[0] carries an audio_id and it conflicts with the top level: either a different top-level audio_id was also provided, or any top-level sound source (sound_file, sound_file_url, sound_file_path, audio_path) was set. A nested audio_id must be the sole audio source.

Source

Thrown at tools/avatar/kling_lip_sync.py:608

        nested_audio_id = str(payload.get("audio_id") or "").strip()
        nested_sound_file = payload.get("sound_file")
        if nested_audio_id and nested_sound_file:
            raise ValueError(
                "Conflicting audio input in face_choose[0]; provide audio_id or sound_file, not both"
            )

        top_level_audio_id = str(inputs.get("audio_id") or "").strip()
        top_level_sound_requested = any(
            inputs.get(key)
            for key in ("sound_file", "sound_file_url", "sound_file_path", "audio_path")
        )

        if nested_audio_id:
            if (
                (top_level_audio_id and top_level_audio_id != nested_audio_id)
                or top_level_sound_requested
            ):
                raise ValueError(
                    "Conflicting audio input between top-level fields and face_choose[0]"
                )
            payload["audio_id"] = nested_audio_id
            return {"type": "audio_id", "value": nested_audio_id}

        if nested_sound_file:
            if top_level_audio_id:
                raise ValueError(
                    "Conflicting audio input between top-level fields and face_choose[0]"
                )
            if top_level_sound_requested:
                top_level_sound_file = normalize_media_input(
                    url=inputs.get("sound_file_url"),
                    path=inputs.get("sound_file_path") or inputs.get("audio_path"),
                    value=inputs.get("sound_file"),
                    label="Lip-sync audio file",
                )
                if top_level_sound_file != nested_sound_file:

View on GitHub (pinned to 95e1c3d0ab)

Solutions

  1. Remove the top-level audio fields when face_choose[0] specifies audio_id
  2. If a global audio is intended, remove audio_id from face_choose[0] and keep only the top-level one
  3. Keep exactly one audio source per call: one of audio_id / sound_file* at one scope

Example fix

# before
inputs = {"sound_file_path": "vo.mp3", "face_choose": [{"face_id": "f1", "audio_id": "audio_B"}]}

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

Strategy: validation

Validate before calling

face_item = (inputs.get("face_choose") or [{}])[0]
nested_id = str(face_item.get("audio_id") or "").strip()
top_sound = any(inputs.get(k) for k in ("sound_file", "sound_file_url", "sound_file_path", "audio_path"))
if nested_id and ((str(inputs.get("audio_id") or "").strip() and str(inputs.get("audio_id")) != nested_id) or top_sound):
    raise ValueError("nested audio_id conflicts with top-level audio")

Prevention

When it happens

Trigger: inputs = {'audio_id': 'audio_A', 'face_choose': [{'audio_id': 'audio_B'}]} (different ids), or inputs = {'sound_file_path': 'vo.mp3', 'face_choose': [{'audio_id': 'audio_B'}]} (nested id + top-level file).

Common situations: Setting a global fallback audio 'just in case' while also specifying per-face audio ids; payloads assembled from two sources (global config + per-shot spec).

Related errors


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