nexu-io/open-design · error · ValueError

avatarMode=upload requires uploadPath for participant {speak

Error message

avatarMode=upload requires uploadPath for participant {speaker}

What it means

Thrown by validate_config() when avatarMode is 'upload' but a configured participant lacks an 'uploadPath'. Upload mode requires every participant to supply a real avatar file; there is no preset fallback. It fires at config validation time, before the transcript is processed.

Source

Thrown at skills/chat-motion-overlay/scripts/build_chat_overlay_spec.py:148

    if config["deliveryFormat"] not in ALLOWED_DELIVERY_FORMATS:
        raise ValueError(f"Unsupported deliveryFormat: {config['deliveryFormat']}")
    if config["container"] == "none" and config["deviceFrame"] == "iphone-dynamic-island":
        raise ValueError("container=none does not support deviceFrame=iphone-dynamic-island; use deviceFrame=none or choose an app container")

    for speaker, participant in config.get("participants", {}).items():
        side = participant.get("side")
        if side and side not in {"left", "right"}:
            raise ValueError(f"Unsupported side for participant {speaker}: {side}")
        preset_key = participant.get("preset")
        if preset_key and preset_key not in PRESET_KEYS:
            raise ValueError(f"Unsupported preset for participant {speaker}: {preset_key}")
        upload_path = participant.get("uploadPath")
        if participant.get("uploadAsset"):
            raise ValueError(f"Participant {speaker} config must use uploadPath, not uploadAsset")
        if config["avatarMode"] == "preset" and upload_path:
            raise ValueError(f"avatarMode=preset does not allow uploadPath for participant {speaker}")
        if config["avatarMode"] == "upload" and not upload_path:
            raise ValueError(f"avatarMode=upload requires uploadPath for participant {speaker}")


def auto_avatar_for_participant(participant_index: int, used_avatar_keys: set[str]) -> str:
    preferred = [*PRESET_KEYS[participant_index:], *PRESET_KEYS[:participant_index]]
    for avatar_key in preferred:
        if avatar_key not in used_avatar_keys:
            return avatar_key
    return PRESET_KEYS[participant_index % len(PRESET_KEYS)]


def configured_participant(speaker: str, config: dict) -> dict:
    return config.get("participants", {}).get(speaker, {})


def build_spec(parsed: dict, config: dict) -> dict:
    meta = parsed["metadata"]
    participants = {}
    used_participant_ids = set()

View on GitHub (pinned to 5be4028344)

Solutions

  1. Add an "uploadPath" pointing at an existing image file for every participant named in the transcript.
  2. If only some participants have uploads, switch avatarMode to 'mixed' (which permits a mix of preset and uploaded avatars).
  3. Remove participants without uploads from the config and rely on auto preset assignment by switching to avatarMode='preset'.

Example fix

// before
{"avatarMode": "upload", "participants": {"闺蜜": {"side": "left", "uploadPath": "/a.png"}, "老婆": {"side": "right", "preset": "female-cat-orange"}}}
// after
{"avatarMode": "upload", "participants": {"闺蜜": {"side": "left", "uploadPath": "/a.png"}, "老婆": {"side": "right", "uploadPath": "/b.png"}}}
Defensive patterns

Strategy: validation

Validate before calling

def validate_upload_mode(config: dict) -> None:
    if config.get("avatarMode") != "upload":
        return
    missing = [name for name, p in config.get("participants", {}).items() if not p.get("uploadPath")]
    if missing:
        raise ValueError(f"avatarMode=upload needs uploadPath for: {missing}")

validate_upload_mode(config)

Prevention

When it happens

Trigger: Run build_chat_overlay_spec.py (or prepare_chat_overlay_bundle.py) with "avatarMode": "upload" and at least one participant entry missing the "uploadPath" key. The run_test_matrix.py case 'invalid_upload_missing_side' exercises exactly this path.

Common situations: Switching avatarMode to 'upload' without backfilling uploadPath for all speakers; a new speaker appears in the transcript but was not added to the participants config; mixing preset-style participant dicts into an upload-mode config.

Related errors


AI-assisted analysis of nexu-io/open-design@5be4028344 (2026-08-12). Data as JSON: /api/errors/c34855e0a5597371. Report an issue: GitHub.