{"record":{"id":"46b2a9050443049d","repo":"nexu-io/open-design","slug":"unsupported-deliveryformat-config-deliveryforma","errorCode":null,"errorMessage":"Unsupported deliveryFormat: {config['deliveryFormat']}","messagePattern":"Unsupported deliveryFormat: (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"skills/chat-motion-overlay/scripts/build_chat_overlay_spec.py","lineNumber":131,"sourceCode":"        validate_config(config)\n        return config\n    user = json.loads(Path(path).read_text(encoding=\"utf-8\"))\n    config.update(user)\n    validate_config(config)\n    return config\n\n\ndef validate_config(config: dict) -> None:\n    if config[\"container\"] not in ALLOWED_CONTAINERS:\n        raise ValueError(f\"Unsupported container: {config['container']}\")\n    if config[\"avatarMode\"] not in ALLOWED_AVATAR_MODES:\n        raise ValueError(f\"Unsupported avatarMode: {config['avatarMode']}\")\n    if config[\"deviceFrame\"] not in ALLOWED_DEVICE_FRAMES:\n        raise ValueError(f\"Unsupported deviceFrame: {config['deviceFrame']}\")\n    if config[\"nicknameMode\"] not in ALLOWED_NICKNAME_MODES:\n        raise ValueError(f\"Unsupported nicknameMode: {config['nicknameMode']}\")\n    if config[\"deliveryFormat\"] not in ALLOWED_DELIVERY_FORMATS:\n        raise ValueError(f\"Unsupported deliveryFormat: {config['deliveryFormat']}\")\n    if config[\"container\"] == \"none\" and config[\"deviceFrame\"] == \"iphone-dynamic-island\":\n        raise ValueError(\"container=none does not support deviceFrame=iphone-dynamic-island; use deviceFrame=none or choose an app container\")\n\n    for speaker, participant in config.get(\"participants\", {}).items():\n        side = participant.get(\"side\")\n        if side and side not in {\"left\", \"right\"}:\n            raise ValueError(f\"Unsupported side for participant {speaker}: {side}\")\n        preset_key = participant.get(\"preset\")\n        if preset_key and preset_key not in PRESET_KEYS:\n            raise ValueError(f\"Unsupported preset for participant {speaker}: {preset_key}\")\n        upload_path = participant.get(\"uploadPath\")\n        if participant.get(\"uploadAsset\"):\n            raise ValueError(f\"Participant {speaker} config must use uploadPath, not uploadAsset\")\n        if config[\"avatarMode\"] == \"preset\" and upload_path:\n            raise ValueError(f\"avatarMode=preset does not allow uploadPath for participant {speaker}\")\n        if config[\"avatarMode\"] == \"upload\" and not upload_path:\n            raise ValueError(f\"avatarMode=upload requires uploadPath for participant {speaker}\")\n","sourceCodeStart":113,"sourceCodeEnd":149,"githubUrl":"https://github.com/nexu-io/open-design/blob/5be4028344c2eb4c667c5a97bda8f750c5597ef7/skills/chat-motion-overlay/scripts/build_chat_overlay_spec.py#L113-L149","documentation":"Raised by validate_config when config['deliveryFormat'] is not in ALLOWED_DELIVERY_FORMATS = {\"mov\",\"webm\",\"json\",\"remotion\",\"hyperframe\",\"preview\"}. Default is 'mov'. The format selects the output artifact: video (mov/webm), a JSON scene spec, a Remotion component, a Hyperframe-ready bundle, or a preview-only render.","triggerScenarios":"User sets `\"deliveryFormat\": \"mp4\"`, `\"deliveryFormat\": \"avi\"`, `\"deliveryFormat\": \"gif\"`, `\"deliveryFormat\": \"png\"`, or `\"deliveryFormat\": \"html\"`. None are recognized.","commonSituations":"Wanting mp4 (not supported — use mov or webm and remux); wanting a GIF (not supported — generate then convert); wanting static frames (not supported); typo or case mismatch ('MOV').","solutions":["Set deliveryFormat to one of: mov, webm, json, remotion, hyperframe, preview.","For an MP4 file, choose 'mov' or 'webm' and remux afterward with ffmpeg if a specific container is required.","For machine consumption / downstream pipelines, use 'json' or 'remotion'.","Pre-validate: `assert c['deliveryFormat'] in {'mov','webm','json','remotion','hyperframe','preview'}`."],"exampleFix":"// before\n{\"deliveryFormat\": \"mp4\"}\n# -> ValueError: Unsupported deliveryFormat: mp4\n\n// after\n{\"deliveryFormat\": \"mov\"}\n# then if you truly need mp4: ffmpeg -i out.mov -c copy out.mp4","handlingStrategy":"validation","validationCode":"ALLOWED_DELIVERY_FORMATS = {\"mov\", \"webm\", \"json\", \"remotion\", \"hyperframe\", \"preview\"}\n\nif config[\"deliveryFormat\"] not in ALLOWED_DELIVERY_FORMATS:\n    raise SystemExit(\n        f\"deliveryFormat must be one of {sorted(ALLOWED_DELIVERY_FORMATS)}; \"\n        f\"got {config['deliveryFormat']!r}. Use 'mov'/'webm' and remux for mp4.\"\n    )","typeGuard":"def is_delivery_format(value) -> bool:\n    return value in {\"mov\", \"webm\", \"json\", \"remotion\", \"hyperframe\", \"preview\"}","tryCatchPattern":"try:\n    validate_config(config)\nexcept ValueError as exc:\n    raise SystemExit(f\"Config error: {exc}\") from exc","preventionTips":["Remember mp4/gif/png are NOT supported; choose mov/webm and post-process.","For pipelines, prefer 'json' or 'remotion' as the machine-readable artifact.","Use jsonschema enum validation at config load.","Document the remux path (ffmpeg) for users who specifically need mp4."],"tags":["config","validation","chat-overlay","delivery","video"],"backgroundTag":null,"analyzedSha":"5be4028344c2eb4c667c5a97bda8f750c5597ef7","analyzedAt":"2026-08-12T12:03:58.812Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}