affaan-m/ECC · error · FalError
views must include 'input_image_url' (the front view)
Error message
views must include 'input_image_url' (the front view)
What it means
image_to_3d accepts an optional views dict of multi-view images, but the fal.ai Tripo-style endpoint requires the front view under the key 'input_image_url'. If views is provided but that key is absent or empty after filtering (only known VIEW_FIELDS with truthy values are kept), the library raises FalError instead of submitting an incomplete payload.
Solutions
- Include 'input_image_url' with a non-empty front-view URL in the views dict
- Verify each views key is one of VIEW_FIELDS and its value is a non-empty URL string
- If you only have one image, omit views entirely and pass it via image_url instead
Example fix
# before
image_to_3d(img, views={'back_image_url': back})
# after
image_to_3d(img, views={'input_image_url': front, 'back_image_url': back}) Defensive patterns
Strategy: validation
Validate before calling
if views is not None:
cleaned = {k: v for k, v in views.items() if v}
assert cleaned.get('input_image_url'), "views requires a non-empty 'input_image_url'" Type guard
def has_front_view(views: dict) -> bool:
return bool(views) and bool(views.get('input_image_url')) Prevention
- Always pass the front view as 'input_image_url' first when using views
- Use only documented VIEW_FIELDS keys — filtered-out typos fail with this error
- Check that view URLs are non-empty strings before calling
- Omit views entirely for single-image input instead of passing partial dicts
When it happens
Trigger: Calling image_to_3d(image_url, views={'back_image_url': 'https://...'}) or views={'input_image_url': None} or views={'input_image_url': ''} — i.e. any views dict that, after filtering to non-empty VIEW_FIELDS keys, lacks 'input_image_url'.
Common situations: Developer misreads the views API and passes only back/side views; keys are correct but values are empty strings or None because upstream URL extraction failed; typo'd key name like 'input_image' that gets filtered out.
Understand the failure class
Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.
Related errors
- image_to_3d needs at least one image
- fps must be positive, got
- image_to_3d needs at least one image
- Invalid Claude plugin root: expected a string
- Invalid Claude target root: expected a non-empty string
AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16).
Data as JSON: /api/errors/242aa435862e09f2.
Report an issue: GitHub.
Appendix: source
Thrown at skills/taste-application/scripts/taste/falapi.py:512
``{"input_image_url": front, "back_image_url": back}``. Passing a bare
list assigns images to :data:`VIEW_FIELDS` in order, which is a guess and
is only correct if the caller actually sorted them that way; a wrong angle
label is worse than omitting the view entirely, because the model trusts
it. When in doubt, send one image.
``pbr`` requests physically-based maps (metallic, roughness, normal). Without
them the mesh lights like painted cardboard in Blender, which defeats the
point of minting it. It is ignored when ``geometry_only`` is set.
Note the endpoint's own input guidance: simple background, single object,
object filling >50% of frame. Busy reference stills - collages, wide shots,
anything with several subjects - produce garbage meshes. Generate a clean
single-object plate first if the pack's stills are not that.
"""
if views:
payload: dict = {k: v for k, v in views.items() if k in VIEW_FIELDS and v}
if "input_image_url" not in payload:
raise FalError("views must include 'input_image_url' (the front view)")
else:
urls = [image_url] if isinstance(image_url, str) else list(image_url)
if not urls:
raise FalError("image_to_3d needs at least one image")
payload = {f: u for f, u in zip(VIEW_FIELDS, urls[:len(VIEW_FIELDS)])}
payload["generate_type"] = "Geometry" if geometry_only else "Normal"
if not geometry_only:
payload["enable_pbr"] = bool(pbr)
if face_count:
# Endpoint range is 40k-1.5M; clamp rather than let it 422.
payload["face_count"] = int(max(40_000, min(1_500_000, face_count)))
result = submit(ENDPOINTS["image_to_3d"], payload, timeout)
return _mesh_url(result, ENDPOINTS["image_to_3d"])
def text_to_3d(prompt: str, *, pbr: bool = True, timeout: int = 900) -> str:View on GitHub (pinned to 8321021c54)