calesthio/OpenMontage · error · ValueError

advanced_lip_sync requires audio_id, sound_file, sound_file_

Error message

advanced_lip_sync requires audio_id, sound_file, sound_file_url, sound_file_path, or audio_path

What it means

Raised by KlingLipSyncTool._copy_audio_input as the final fallback: no audio source exists anywhere — no audio_id and normalize_media_input over sound_file/sound_file_url/sound_file_path/audio_path produced nothing. Lip-sync without audio is meaningless, so the tool refuses before calling Kling.

Source

Thrown at tools/avatar/kling_lip_sync.py:644

                if top_level_sound_file != nested_sound_file:
                    raise ValueError(
                        "Conflicting audio input between top-level fields and face_choose[0]"
                    )
            return {"type": "sound_file", "source": "face_choose[0]"}

        if top_level_audio_id:
            payload["audio_id"] = top_level_audio_id
            return {"type": "audio_id", "value": top_level_audio_id}

        sound_path = inputs.get("sound_file_path") or inputs.get("audio_path")
        sound_file = normalize_media_input(
            url=inputs.get("sound_file_url"),
            path=sound_path,
            value=inputs.get("sound_file"),
            label="Lip-sync audio file",
        )
        if not sound_file:
            raise ValueError("advanced_lip_sync requires audio_id, sound_file, sound_file_url, sound_file_path, or audio_path")
        payload["sound_file"] = sound_file
        return {
            "type": "sound_file",
            "source": inputs.get("sound_file_url") or sound_path or "inline",
        }

    def _download_videos(
        self,
        client: KlingClient,
        outputs: list[dict[str, Any]],
        inputs: dict[str, Any],
    ) -> list[Path]:
        if not outputs:
            raise ValueError("Kling lip-sync response contained no videos")
        base_path = Path(inputs.get("output_path", "kling_lip_sync.mp4"))
        paths: list[Path] = []
        for index, item in enumerate(outputs):
            url = self._output_url(item)

View on GitHub (pinned to 95e1c3d0ab)

Solutions

  1. Provide exactly one of: audio_id, sound_file, sound_file_url, sound_file_path, or audio_path
  2. Check for typos in the audio field names
  3. If using sound_file_path, verify the file exists before the call

Example fix

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

# after
inputs = {"video_id": vid, "face_choose": [{"face_id": "f1", "sound_file_path": "/tmp/vo.mp3"}]}
Defensive patterns

Strategy: validation

Validate before calling

has_audio = any([
    str(inputs.get("audio_id") or "").strip(),
    inputs.get("sound_file"),
    inputs.get("sound_file_url"),
    (inputs.get("sound_file_path") and __import__("pathlib").Path(inputs["sound_file_path"]).is_file()),
    (inputs.get("audio_path") and __import__("pathlib").Path(inputs["audio_path"]).is_file()),
])
if not has_audio:
    raise ValueError("no audio source for lip-sync")

Type guard

def has_lip_sync_audio(inputs) -> bool:
    return any(inputs.get(k) for k in ("audio_id", "sound_file", "sound_file_url", "sound_file_path", "audio_path"))

Prevention

When it happens

Trigger: Calling kling_lip_sync with only video_id/face_choose and every audio field absent, empty string, or None. Also when sound_file_path points at a non-existent path such that normalization yields falsy (with no URL/value to fall back on).

Common situations: Forgetting the voiceover in an automated pipeline; audio field named something else in the caller's dict (typo like sound_filepath); empty-string defaults from a config loader.

Related errors


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