affaan-m/ECC · error · FalError

no URL in provider response; response shape may have…

Error message

no URL in provider response; response shape may have changed (provider payload omitted)

What it means

falapi.parse_urls found no downloadable asset URL in the JSON returned by a fal.ai endpoint, so first_url cannot return a result and raises FalError. The library treats this as a sign that the provider's response schema changed or the model produced no output. It is a defensive guard against silently returning an empty/None URL to callers like _mesh_url, retopologize, split_parts, images_to_video, reference_to_video, and extract_frame.

Solutions

  1. Print/log the raw provider response (result) to inspect the actual keys and find where the URL now lives
  2. Check fal.ai docs/changelog for the endpoint used in ENDPOINTS and update parse_urls to the new response shape
  3. Retry the generation — transient model failures can return an empty payload; also verify the input passed safety/size checks
  4. Pin the model endpoint version on fal.ai so schema changes don't silently break the client

Example fix

// before
url = first_url(result, ENDPOINTS['images_to_video'])
// after
urls = parse_urls(result)
if not urls:
    print(json.dumps(result, indent=2))  # inspect real payload keys
    raise FalError('images_to_video returned no URL; inspect payload above')
Defensive patterns

Strategy: try-catch

Validate before calling

urls = parse_urls(result)
if not urls:
    # decide fallback before calling first_url
    ...

Type guard

def has_urls(result) -> bool:
    return bool(parse_urls(result))

Try / catch

try:
    url = first_url(result, endpoint)
except FalError:
    logger.warning('no asset URL for %s; retrying', endpoint)
    url = first_url(submit(endpoint, payload, timeout), endpoint)  # one retry

Prevention

When it happens

Trigger: Any wrapper call (_mesh_url, retopologize, split_parts, images_to_video, reference_to_video, extract_frame, merge_videos) whose fal.ai endpoint returns 200 with a payload containing no URL fields (e.g. missing 'video_url'/'image_url'/'mesh_url' keys), an empty output object, or a qualitatively failed generation that still reports success.

Common situations: fal.ai changes an endpoint's response schema after a model upgrade; the queue request succeeded but the model returned no artifact (e.g. safety filter rejected the generation); calling extract_frame with a timestamp beyond the video length; an API version mismatch between the client payload and the deployed model.

Understand the failure class

Background: "invalid response format", "malformed payload", "missing data field": when an API returns 200 but the response shape is wrong — this error's family across 23 libraries.

Related errors


AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16). Data as JSON: /api/errors/8e4fa96b9b5a40db. Report an issue: GitHub.

Appendix: source

Thrown at skills/taste-application/scripts/taste/falapi.py:370

        elif isinstance(node, dict):
            if isinstance(node.get("url"), str):
                found.append(node["url"])
            for k, v in node.items():
                if k != "url":
                    walk(v)
        elif isinstance(node, (list, tuple)):
            for v in node:
                walk(v)

    walk(result)
    seen: set[str] = set()
    return [u for u in found if not (u in seen or seen.add(u))]


def first_url(result: Any, endpoint: str) -> str:
    urls = parse_urls(result)
    if not urls:
        raise FalError(
            "no URL in provider response; response shape may have changed "
            "(provider payload omitted)"
        )
    return urls[0]


def _mesh_url(result: Any, endpoint: str) -> str:
    """The GLB out of a 3D response, addressed by key rather than by position.

    ``first_url`` would work only as long as ``model_glb`` happens to be the
    first URL-bearing key in the response. It is today; the response also
    carries a ``thumbnail`` PNG and a ``model_urls`` block with obj/fbx/mtl,
    so a key reordering upstream would quietly start returning a preview image
    where a mesh is expected - and a preview image downloads fine, so nothing
    would fail until Blender refused to open it.
    """
    if isinstance(result, dict):
        for path in (("model_glb", "url"), ("model_urls", "glb", "url"),

View on GitHub (pinned to 8321021c54)