BerriAI/litellm · error · BlackForestLabsError

Polling failed: {response.text}

Error message

Polling failed: {response.text}

What it means

During the sync polling loop, each GET to the polling_url must return 200. A single non-200 poll (auth expiry mid-poll, 429 throttling, 5xx blips, or the polling URL expiring) aborts the loop and re-raises with the upstream status and body. The job may or may not still be running on BFL's side.

Source

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

        # 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(
                url=polling_url,
                headers=polling_headers,
            )

            if response.status_code != 200:
                raise BlackForestLabsError(
                    status_code=response.status_code,
                    message=f"Polling failed: {response.text}",
                )

            data = response.json()
            status = data.get("status")

            verbose_logger.debug("BFL poll status: %s", status)

            if status == "Ready":
                return response
            elif status in [
                "Error",
                "Failed",
                "Content Moderated",
                "Request Moderated",
            ]:
                raise BlackForestLabsError(

View on GitHub (pinned to 6c2dcb801b)

Solutions

  1. Read the embedded response body — 429 means back off (raise interval), 404 means the job/URL expired (resubmit), 5xx means retry the whole call once.
  2. Increase the polling interval so BFL is not throttling you.
  3. For 401, verify the key is still valid; keys rotated mid-job kill polling auth.
  4. Resubmit the generation — a dead polling session cannot be resumed through this API.
Defensive patterns

Strategy: retry

Validate before calling

null

Type guard

null

Try / catch

from litellm.exceptions import APIError

try:
    img = litellm.image_generation(model=M, prompt=p)
except APIError as e:
    sc = getattr(e, "status_code", None)
    if sc == 429:
        increase_interval_and_retry()
    elif sc == 404:
        return litellm.image_generation(model=M, prompt=p)  # URL expired -> resubmit
    elif sc and sc >= 500:
        return litellm.image_generation(model=M, prompt=p)
    raise

Prevention

When it happens

Trigger: Any poll response != 200 during the window: 401 if the key is invalidated mid-job, 429 when polling faster than BFL tolerates, 404 when the polling_url expires or the job record ages out, 5xx transient gateway errors.

Common situations: Aggressive polling intervals combined with BFL throttling; long-running jobs whose polling URLs expire; key rotation during an in-flight job; BFL incidents.

Related errors


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