nexu-io/open-design · error · ValueError

Unsupported container: {config['container']}

Error message

Unsupported container: {config['container']}

What it means

Raised by validate_config in build_chat_overlay_spec.py when config['container'] is not in ALLOWED_CONTAINERS = {"none","wechat","telegram","messenger"}. The config is built by deep-copying DEFAULT_CONFIG (container='wechat') then overlaying the user JSON, so this fires only when the user's config sets container to an unrecognized string.

Source

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

def is_flag(value: str) -> bool:
    return value.strip().lower() == "highlight"


def load_config(path: str | None) -> dict:
    config = json.loads(json.dumps(DEFAULT_CONFIG))
    if not path:
        validate_config(config)
        return config
    user = json.loads(Path(path).read_text(encoding="utf-8"))
    config.update(user)
    validate_config(config)
    return config


def validate_config(config: dict) -> None:
    if config["container"] not in ALLOWED_CONTAINERS:
        raise ValueError(f"Unsupported container: {config['container']}")
    if config["avatarMode"] not in ALLOWED_AVATAR_MODES:
        raise ValueError(f"Unsupported avatarMode: {config['avatarMode']}")
    if config["deviceFrame"] not in ALLOWED_DEVICE_FRAMES:
        raise ValueError(f"Unsupported deviceFrame: {config['deviceFrame']}")
    if config["nicknameMode"] not in ALLOWED_NICKNAME_MODES:
        raise ValueError(f"Unsupported nicknameMode: {config['nicknameMode']}")
    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}")

View on GitHub (pinned to 5be4028344)

Solutions

  1. Set container to one of: none, wechat, telegram, messenger.
  2. Use lowercase exactly as listed (the check is case-sensitive).
  3. If you need no app chrome, use 'none' (but note the deviceFrame constraint in error 576).
  4. Validate the config JSON before running: `python3 -c "import json; c=json.load(open('cfg.json')); assert c['container'] in {'none','wechat','telegram','messenger'}"`.

Example fix

// before (cfg.json)
{"container": "whatsapp"}
# -> ValueError: Unsupported container: whatsapp

// after
{"container": "telegram"}
Defensive patterns

Strategy: validation

Validate before calling

ALLOWED_CONTAINERS = {"none", "wechat", "telegram", "messenger"}

if config["container"] not in ALLOWED_CONTAINERS:
    raise SystemExit(
        f"container must be one of {sorted(ALLOWED_CONTAINERS)}; got {config['container']!r}"
    )

Type guard

def is_container(value) -> bool:
    return value in {"none", "wechat", "telegram", "messenger"}

Try / catch

try:
    validate_config(config)
except ValueError as exc:
    raise SystemExit(f"Config error: {exc}") from exc

Prevention

When it happens

Trigger: User supplies a config JSON with `"container": "whatsapp"` or `"container": "line"`, a typo like `"WeChat"` (case-sensitive), or `"container": "slack"`. Also fires on null/number values via JSON.

Common situations: Guessing container names from common chat apps not in the allowed set; case mismatch (WeChat vs wechat); legacy config from a previous version where the allowed set differed; copying an example from an unrelated tool.

Related errors


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