BerriAI/litellm · error · BlackForestLabsError

No polling_url in BFL response

Error message

No polling_url in BFL response

What it means

Sync BFL flow: the initial response was JSON with HTTP < 400 and no `errors` key, but the `polling_url` field is missing, so LiteLLM cannot start polling and raises BlackForestLabsError(500). The expected contract is a submission response containing `polling_url` (BFL's async task model: submit, then poll until status == Ready). A missing field means an unexpected payload shape - contract change, or a custom base_url serving a BFL-incompatible API.

Solutions

  1. Upgrade LiteLLM to the latest version (schema fixes land there).
  2. Log the full initial response body to see which field replaced `polling_url`, if any.
  3. Verify base_url points at the generation submit endpoint and not a status/health route.
  4. If mocking BFL, include `{"id": ..., "status": "Queued", "polling_url": "https://..."}` in the submit response.
Defensive patterns

Strategy: try-catch

Try / catch

from litellm.llms.black_forest_labs.common_utils import BlackForestLabsError

try:
    resp = litellm.image_generation(model="flux-pro-1.1", prompt=p)
except BlackForestLabsError as e:
    if "No polling_url" in str(e):
        log.error("BFL submit response missing polling_url - schema drift or wrong base_url")
        raise
    raise

Prevention

When it happens

Trigger: BFL changes its submission-response schema (field renamed/moved); `api_base`/base_url pointing at a stub or third-party gateway that returns 200 JSON without polling_url; an intermediate cache returning a stale/partial response body.

Common situations: Old LiteLLM versions after BFL schema evolution; prototypes mocking the BFL API for tests without implementing polling_url; misrouted base_url hitting a status endpoint instead of the generation-submit endpoint.

Related errors


AI-assisted analysis of BerriAI/litellm@77b7c6c40c (2026-08-18). Data as JSON: /api/errors/8da8bce1e40a6d37. Report an issue: GitHub.

Appendix: source

Thrown at litellm/llms/black_forest_labs/image_generation/handler.py:324

        # Parse initial response to get polling URL
        try:
            response_data: Final = initial_response.json()
        except Exception as e:
            raise BlackForestLabsError(
                status_code=initial_response.status_code,
                message=f"Error parsing initial response: {e}",
            )

        # Check for immediate errors
        if "errors" in response_data:
            raise BlackForestLabsError(
                status_code=initial_response.status_code,
                message=f"BFL error: {response_data['errors']}",
            )

        polling_url: Final = response_data.get("polling_url")
        if not polling_url:
            raise BlackForestLabsError(
                status_code=500,
                message="No polling_url in BFL response",
            )

        # Reject polling URLs that don't belong to BFL-controlled infrastructure.
        # BFL uses regional subdomains (e.g. gateway.bfl.ai) that differ from the
        # submission host (api.bfl.ai), so we validate against the registered
        # domain rather than doing a strict same-origin check. VERIA-51.
        assert_bfl_polling_url(polling_url)

        # Get just the auth header for polling
        polling_headers: Final = {"x-key": headers.get("x-key", "")}

        start_time: Final = time.time()
        verbose_logger.debug("BFL starting sync polling at %s", polling_url)

        while time.time() - start_time < max_wait:
            response = sync_client.get(

View on GitHub (pinned to 77b7c6c40c)