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
- Set container to one of: none, wechat, telegram, messenger.
- Use lowercase exactly as listed (the check is case-sensitive).
- If you need no app chrome, use 'none' (but note the deviceFrame constraint in error 576).
- 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
- Validate config with jsonschema before running the build.
- Keep allowed-value sets in one place and generate docs/help from them.
- Treat config values as case-sensitive lowercase enums.
- Fail fast at config load, not deep in the render pipeline.
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
- existing config at ${where} is not valid JSON: ${err instanc
- existing config at ${where} is not a JSON object
- Unsupported avatarMode: {config['avatarMode']}
- Unsupported deviceFrame: {config['deviceFrame']}
- Unsupported nicknameMode: {config['nicknameMode']}
AI-assisted analysis of nexu-io/open-design@5be4028344 (2026-08-12).
Data as JSON: /api/errors/b68cf6349d65c865.
Report an issue: GitHub.