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
- 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.
- Set a 'preset' under the participant's config entry so the transcript hint is ignored.
- 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
- Prefer setting participant 'preset' in config over inline transcript avatar hints.
- Lint the transcript avatar tokens against PRESET_KEYS before invoking the builder.
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
- avatarMode=preset does not allow uploadPath for participant
- avatarMode=upload requires uploadPath for participant {speak
- Participant {speaker} appears on both {participant['side']}
- Participant {speaker} has conflicting transcript avatar hint
- avatarMode=mixed requires at least one upload path
AI-assisted analysis of nexu-io/open-design@5be4028344 (2026-08-12).
Data as JSON: /api/errors/82f3bdd55c45ba96.
Report an issue: GitHub.