{"record":{"id":"fb3db7a6163f3cd0","repo":"calesthio/OpenMontage","slug":"model-accepts-at-most-limits-images-images","errorCode":null,"errorMessage":"{model} accepts at most {limits['images']} images, {limits['videos']} videos, and {limits['audios']} audio references","messagePattern":"(.+?) accepts at most (.+?) images, (.+?) videos, and (.+?) audio references","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"tools/video/atlas_video.py","lineNumber":254,"sourceCode":"            if not image:\n                raise ValueError(\"image_to_video requires image_url, image_path, or reference_image_path\")\n            payload[\"image\"] = image\n            if last_image:\n                payload[\"last_image\" if style == \"seedance_image\" else \"end_image\"] = last_image\n        elif style == \"gemini_images\":\n            if image and not images:\n                images = [image]\n            if not images:\n                raise ValueError(\"This Gemini route requires at least one reference image\")\n            payload[\"images\"] = images\n        elif style == \"seedance_references\":\n            if image and not images:\n                images = [image]\n            if not (images or videos or (audios and spec[\"family\"] == \"bytedance/seedance-2.5\")):\n                raise ValueError(\"reference_to_video requires supported reference media for the selected model\")\n            limits = spec[\"media_limits\"]\n            if len(images) > limits[\"images\"] or len(videos) > limits[\"videos\"] or len(audios) > limits[\"audios\"]:\n                raise ValueError(\n                    f\"{model} accepts at most {limits['images']} images, {limits['videos']} videos, \"\n                    f\"and {limits['audios']} audio references\"\n                )\n            if images:\n                payload[\"reference_images\"] = images\n            if videos:\n                payload[\"reference_videos\"] = videos\n            if audios:\n                payload[\"reference_audios\"] = audios\n        elif style == \"h3_refers\":\n            refers = list(inputs.get(\"refers\") or [])\n            if not refers:\n                refers = [\n                    *({\"url\": value, \"type\": \"image\"} for value in images),\n                    *({\"url\": value, \"type\": \"video\"} for value in videos),\n                    *({\"url\": value, \"type\": \"audio\"} for value in audios),\n                ]\n                if image:","sourceCodeStart":236,"sourceCodeEnd":272,"githubUrl":"https://github.com/calesthio/OpenMontage/blob/95e1c3d0ab93482159818560f6a8c8e866b9139f/tools/video/atlas_video.py#L236-L272","documentation":"Raised in _build_payload for seedance_references styles when the number of supplied images/videos/audios exceeds the per-model caps stored in spec['media_limits']. It is a hard client-side cap check done before payload submission.","triggerScenarios":"Passing 11 reference_images to a model whose media_limits['images'] is 10; mixing a promoted lone image plus a full reference_images list so the effective count crosses the cap; batch pipelines that fan out N references without clamping.","commonSituations":"Upgrading a workflow from seedance-2.0 (smaller caps) to more references than it allows, or downgrading a 2.5 workflow (up to 30 images) to a 2.0 model; not realizing the lone image_url is prepended to reference_images and counts toward the limit.","solutions":["Read the message — it states the exact caps for your model; trim each list to fit (e.g. images[:limits['images']])","Remember the lone image promotion: if you pass image_url AND reference_images, the image is added to the list, so budget for it","For larger reference sets, switch to a model family with higher media_limits (bytedance/seedance-2.5)"],"exampleFix":"# before\ninputs = {'model': model, 'reference_images': all_30_frames}  # exceeds cap on seedance-2.0\n\n# after\nlimits = atlas_video.get_info()['model_catalog'][model]['media_limits']\ninputs = {'model': model, 'reference_images': all_30_frames[:limits['images']]}","handlingStrategy":"validation","validationCode":"spec = atlas_video.get_info()['model_catalog'][model]\nlim = spec['media_limits']\ninputs['reference_images'] = inputs.get('reference_images', [])[:lim['images']]\ninputs['reference_videos'] = inputs.get('reference_videos', [])[:lim['videos']]\ninputs['reference_audios'] = inputs.get('reference_audios', [])[:lim['audios']]","typeGuard":"def within_media_limits(inputs: dict, lim: dict) -> bool:\n    return (len(inputs.get('reference_images') or []) <= lim['images'] and\n            len(inputs.get('reference_videos') or []) <= lim['videos'] and\n            len(inputs.get('reference_audios') or []) <= lim['audios'])","tryCatchPattern":"try:\n    result = atlas_video.run(inputs=inputs)\nexcept ValueError as e:\n    if 'accepts at most' in str(e):\n        # parse caps from message or refetch spec, trim, retry once\n        trim_to_limits(inputs)\n        result = atlas_video.run(inputs=inputs)\n    else:\n        raise","preventionTips":["Always clamp lists with [:limit] from the live spec","Remember a lone image_url is added to reference_images and counts toward the cap","Re-read media_limits when swapping model families — caps differ between 2.0 and 2.5"],"tags":["atlas-cloud","seedance","video-generation","limits","validation"],"backgroundTag":null,"analyzedSha":"95e1c3d0ab93482159818560f6a8c8e866b9139f","analyzedAt":"2026-08-15T06:31:20.014Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}