{"record":{"id":"d54a61137435e0c5","repo":"calesthio/OpenMontage","slug":"layer-decomposition-requires-exactly-one-source-im","errorCode":null,"errorMessage":"layer decomposition requires exactly one source image","messagePattern":"layer decomposition requires exactly one source image","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"tools/graphics/atlas_image.py","lineNumber":173,"sourceCode":"                width, height, _COMMON_RATIOS\n            )\n        elif style == \"tier\":\n            payload[\"size\"] = inputs.get(\"resolution\", \"auto\")\n\n        images = list(inputs.get(\"image_urls\") or [])\n        if inputs.get(\"image_url\"):\n            images.insert(0, inputs[\"image_url\"])\n        media_style = spec[\"media_style\"]\n        if media_style == \"images\":\n            maximum = int(spec[\"max_images\"])\n            if not images:\n                raise ValueError(f\"{spec['operation']} requires at least one source image\")\n            if len(images) > maximum:\n                raise ValueError(f\"{model} accepts at most {maximum} source images\")\n            payload[\"images\"] = images\n        elif media_style == \"image\":\n            if len(images) != 1:\n                raise ValueError(\"layer decomposition requires exactly one source image\")\n            payload[\"image\"] = images[0]\n\n        for field in spec.get(\"optional_fields\", ()):\n            if inputs.get(field) is not None:\n                payload[field] = inputs[field]\n        if inputs.get(\"output_format\") and inputs[\"output_format\"] != \"default\":\n            payload[\"output_format\"] = inputs[\"output_format\"]\n\n        extra = inputs.get(\"extra_params\")\n        if isinstance(extra, dict):\n            payload.update(extra)\n        return payload\n\n    @staticmethod\n    def _upload_value(value: str, api_key: str) -> str:\n        return value if _is_remote(value) else atlas_client.upload_media(value, api_key)\n\n    def _resolve_media(self, inputs: dict[str, Any], api_key: str) -> dict[str, Any]:","sourceCodeStart":155,"sourceCodeEnd":191,"githubUrl":"https://github.com/calesthio/OpenMontage/blob/95e1c3d0ab93482159818560f6a8c8e866b9139f/tools/graphics/atlas_image.py#L155-L191","documentation":"ValueError raised in _build_payload for single-image ('image' media_style) models — the layer decomposition operation — when the collected images list does not contain exactly one entry. It fires both for zero images and for two or more, since payload['image'] takes a single URL.","triggerScenarios":"Calling layer decomposition with an empty images list (no image_url/image_urls), or passing multiple URLs (e.g. image_url plus a non-empty image_urls list) when the operation accepts exactly one.","commonSituations":"Generic wrappers that always pass image_urls arrays hitting a single-image endpoint; combining the singular and plural fields; forgetting the input image for a decomposition request.","solutions":["Pass exactly one image: either image_url='...' alone or image_urls=[single_url].","Normalize your pipeline to one canonical field and drop the other before calling single-image operations.","Validate `len(images) == 1` upstream with a clear error if callers may supply arrays.","For multi-image needs use a model whose media_style is 'images', not the decomposition model."],"exampleFix":"# before\ninputs = {\"model\": m, \"image_urls\": [front, back]}  # decomposition -> ValueError\n\n# after\ninputs = {\"model\": m, \"image_url\": front}  # exactly one source image","handlingStrategy":"validation","validationCode":"images = list(inputs.get(\"image_urls\") or [])\nif inputs.get(\"image_url\"):\n    images.insert(0, inputs[\"image_url\"])\nassert len(images) == 1, \"layer decomposition needs exactly one source image\"","typeGuard":"def exactly_one_image(inputs: dict) -> bool:\n    n = len(inputs.get(\"image_urls\") or []) + (1 if inputs.get(\"image_url\") else 0)\n    return n == 1","tryCatchPattern":"try:\n    result = tool.run(inputs)\nexcept ValueError as e:\n    if \"exactly one source image\" in str(e):\n        result = tool.run({**inputs, \"image_url\": inputs[\"image_urls\"][0], \"image_urls\": None})\n    else:\n        raise","preventionTips":["For single-image operations pass only image_url; drop image_urls entirely.","Normalize your input schema per operation (singular vs plural) in a pre-call validation layer.","Add unit tests asserting the single-image invariant for decomposition calls."],"tags":["atlas-cloud","image","input-validation","layer-decomposition"],"backgroundTag":null,"analyzedSha":"95e1c3d0ab93482159818560f6a8c8e866b9139f","analyzedAt":"2026-08-15T06:31:20.014Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}