nexu-io/open-design · error · ValueError

Unsupported avatar key for participant {speaker}: {avatar_ke

Error message

Unsupported avatar key for participant {speaker}: {avatar_key}

What it means

Thrown in build_spec() when the resolved avatar_key for a new speaker is not one of the six PRESET_KEYS. The key is resolved in priority order: config participant 'preset', then the transcript message's inline avatar hint, then auto assignment from PRESET_KEYS. If the chosen value is not in the preset library, building aborts.

Source

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

    meta = parsed["metadata"]
    participants = {}
    used_participant_ids = set()
    order = []
    messages = []
    start = int(meta["start"])
    gap = int(meta["gap"])
    for index, message in enumerate(parsed["messages"]):
        speaker = message["speaker"]
        if speaker not in participants:
            order.append(speaker)
            configured = configured_participant(speaker, config)
            inferred_side = "left" if len(order) == 1 else "right" if len(order) == 2 else "left"
            side = configured.get("side") or message["side"] or inferred_side
            avatar_key = configured.get("preset") or message["avatar"] or auto_avatar_for_participant(
                len(order) - 1, {p["avatarKey"] for p in participants.values()}
            )
            if avatar_key not in PRESET_KEYS:
                raise ValueError(f"Unsupported avatar key for participant {speaker}: {avatar_key}")
            participant = {
                "id": unique_slug(slugify(speaker), used_participant_ids),
                "name": speaker,
                "side": side,
                "avatarKey": avatar_key,
            }
            used_participant_ids.add(participant["id"])
            if config["avatarMode"] in {"upload", "mixed"} and configured.get("uploadPath"):
                participant["uploadPath"] = configured["uploadPath"]
            if config["avatarMode"] == "upload" and not participant.get("uploadPath"):
                raise ValueError(f"avatarMode=upload requires uploadPath for participant {speaker}")
            participants[speaker] = participant
        participant = participants[speaker]
        side = message["side"] or participant["side"]
        if side != participant["side"]:
            raise ValueError(f"Participant {speaker} appears on both {participant['side']} and {side}; use one side per participant")
        avatar_key = participant["avatarKey"]
        if message["avatar"] and message["avatar"] != participant["avatarKey"] and not configured_participant(speaker, config).get("preset"):

View on GitHub (pinned to 5be4028344)

Solutions

  1. Use one of the valid preset keys: female-bunny-pink, female-cat-orange, female-fox-yellow, male-bear-mint, male-penguin-blue, male-koala-lilac.
  2. Set a 'preset' under the participant's config entry so the transcript hint is ignored.
  3. Omit the avatar field from the transcript line entirely so auto_avatar_for_participant assigns a valid key.

Example fix

// before (transcript)
Alice|left|not-a-preset|你好
// after
Alice|left|female-fox-yellow|你好
Defensive patterns

Strategy: validation

Validate before calling

PRESET_KEYS = {"female-bunny-pink","female-cat-orange","female-fox-yellow","male-bear-mint","male-penguin-blue","male-koala-lilac"}
def check_transcript_avatars(transcript_lines, config):
    for line in transcript_lines:
        parts = [p.strip() for p in line.split("|")] if "|" in line else []
        if not parts or len(parts) < 3:
            continue
        speaker = parts[0]
        avatar = parts[-2] if len(parts) >= 4 else None
        if avatar and avatar not in PRESET_KEYS and not config.get("participants", {}).get(speaker, {}).get("preset"):
            raise ValueError(f"invalid avatar '{avatar}' for {speaker}; set a config preset or use a preset key")

Type guard

def is_preset_key(value: str) -> bool:
    return value in {"female-bunny-pink","female-cat-orange","female-fox-yellow","male-bear-mint","male-penguin-blue","male-koala-lilac"}

Prevention

When it happens

Trigger: A transcript line uses the 3-or-4 pipe form whose avatar field is a non-preset token (e.g. `Alice|left|not-a-preset|hi`), and the participant has no config 'preset' override. The run_test_matrix.py case 'invalid_transcript_avatar_key' reproduces this.

Common situations: Typing a free-form avatar name in the transcript instead of a preset key; using an old/wrong preset name after the PRESET_KEYS list changed; leaving an avatar hint that was meant to be a filename.

Related errors


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