nexu-io/open-design · error · ValueError
Unsupported deviceFrame: {config['deviceFrame']}
Error message
Unsupported deviceFrame: {config['deviceFrame']} What it means
Raised by validate_config when config['deviceFrame'] is not in ALLOWED_DEVICE_FRAMES = {"none","iphone-dynamic-island"}. Default is 'iphone-dynamic-island'. Note the cross-field constraint: container='none' combined with deviceFrame='iphone-dynamic-island' is rejected separately (error 576).
Source
Thrown at skills/chat-motion-overlay/scripts/build_chat_overlay_spec.py:127
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}")
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:View on GitHub (pinned to 5be4028344)
Solutions
- Set deviceFrame to one of: none, iphone-dynamic-island.
- If container is 'none', you MUST use deviceFrame 'none' (iphone-dynamic-island requires an app container — see error 576).
- For an unsupported device frame, request it upstream or render without a frame (deviceFrame=none).
- Pre-validate: `assert c['deviceFrame'] in {'none','iphone-dynamic-island'}`.
Example fix
// before
{"deviceFrame": "pixel"}
# -> ValueError: Unsupported deviceFrame: pixel
// after
{"deviceFrame": "iphone-dynamic-island", "container": "wechat"} Defensive patterns
Strategy: validation
Validate before calling
ALLOWED_DEVICE_FRAMES = {"none", "iphone-dynamic-island"}
if config["deviceFrame"] not in ALLOWED_DEVICE_FRAMES:
raise SystemExit(
f"deviceFrame must be one of {sorted(ALLOWED_DEVICE_FRAMES)}; "
f"got {config['deviceFrame']!r}"
) Type guard
def is_device_frame(value) -> bool:
return value in {"none", "iphone-dynamic-island"} Try / catch
try:
validate_config(config)
except ValueError as exc:
raise SystemExit(f"Config error: {exc}") from exc Prevention
- Remember deviceFrame is coupled to container (none container requires none frame).
- Use the exact lowercase token 'iphone-dynamic-island'.
- Catch this at config load via jsonschema enum.
- If you need an unsupported frame, render with 'none' and composite externally.
When it happens
Trigger: User sets `"deviceFrame": "pixel"`, `"deviceFrame": "iphone-notch"`, `"deviceFrame": "android"`, or any frame name not in the allowed set.
Common situations: Wanting an Android frame not yet supported; guessing iPhone variant names ('notch', 'xs'); typo; legacy config; combining 'none' container with a frame that the script does not whitelist.
Related errors
- container=none does not support deviceFrame=iphone-dynamic-i
- Unsupported container: {config['container']}
- Unsupported avatarMode: {config['avatarMode']}
- Unsupported nicknameMode: {config['nicknameMode']}
- Unsupported deliveryFormat: {config['deliveryFormat']}
AI-assisted analysis of nexu-io/open-design@5be4028344 (2026-08-12).
Data as JSON: /api/errors/1756a30db9e59289.
Report an issue: GitHub.