BerriAI/litellm · error · BlackForestLabsError

No polling_url in BFL response

Error message

No polling_url in BFL response

What it means

The submission JSON parsed cleanly and carried no 'errors' key, but the polling_url field BFL is supposed to return is absent. The handler needs that URL to track the job, so it raises a 500 BlackForestLabsError. Usually indicates an API schema drift, an unexpected response from a custom api_base, or BFL returning an error shape not caught by the 'errors' check.

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 6c2dcb801b)

Solutions

  1. Log the full submission JSON on failure to see which schema actually arrived.
  2. Confirm api_base targets the official BFL endpoint or a fully schema-compatible one.
  3. Upgrade LiteLLM — newer releases track BFL schema changes.
  4. If BFL itself changed the contract, patch response_data.get("polling_url") to the new key upstream of your deployment.
Defensive patterns

Strategy: try-catch

Validate before calling

null

Type guard

null

Try / catch

try:
    img = litellm.image_generation(model=M, prompt=p)
except Exception as e:
    if "No polling_url" in str(e):
        log.critical("BFL schema drift or bad api_base: %s", e)
    raise

Prevention

When it happens

Trigger: A 2xx submission response whose JSON has neither polling_url nor errors — e.g. a different BFL API version, a mock/gateway response, or a body like {"id": ...} from an unmapped schema.

Common situations: Custom api_base pointing at a BFL-compatible service with a different response contract; BFL API revision that changed the job envelope; test doubles returning simplified responses.

Related errors


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