BerriAI/litellm · error · BlackForestLabsError

BFL initial request failed

Error message

BFL initial request failed: {initial_response.text}

What it means

In the sync BFL polling flow, the initial generation POST returned an HTTP status >= 400 and the handler re-raises it verbatim as BlackForestLabsError with the upstream status code and body text. Unlike 'Request failed', this is a real HTTP response from BFL (or whatever serves your base_url), so the status code and body carry the diagnosis (401 bad key, 422 bad params, 429 rate limit, 404 wrong endpoint/model).

Solutions

  1. Match the status code: 401/403 -> fix BFL_API_KEY / plan access; 422 -> fix request params per the BFL API docs; 429 -> slow down or add retries with backoff; 404 -> fix base_url/model id.
  2. Print the full message body - BFL includes a human-readable reason in the JSON it returns.
  3. Confirm the key works directly: `curl -H "x-key: $BFL_API_KEY" https://api.bfl.ai/v1/...`.
  4. Check your BFL account credits/billing if generation previously worked.

Example fix

# before: model id typo / unsupported params
resp = litellm.image_generation(model="flux-pro-1.5", width=123, height=456, prompt="sunset")

# after: valid model + allowed dimensions
resp = litellm.image_generation(model="flux-pro-1.1", width=1024, height=768, prompt="sunset")
Defensive patterns

Strategy: try-catch

Validate before calling

import os, urllib.request, json

def bfl_key_valid(key: str) -> bool:
    req = urllib.request.Request(
        "https://api.bfl.ai/v1/flux-pro-1.1",  # lightweight endpoint per BFL docs
        headers={"x-key": key, "Content-Type": "application/json"},
        method="POST", data=json.dumps({"prompt": "ping"}).encode(),
    )
    try:
        urllib.request.urlopen(req, timeout=10)
        return True
    except urllib.error.HTTPError as e:
        return e.code not in (401, 403)   # 422/429 still means the key is accepted
    except Exception:
        return False

assert bfl_key_valid(os.environ["BFL_API_KEY"]) or warn("BFL key rejected")

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 e.status_code in (401, 403):
        rotate_bfl_key()                      # auth path
    elif e.status_code == 422:
        fix_request_params(e)                 # body names the bad field
    elif e.status_code == 429:
        schedule_retry_backoff(e)
    else:
        raise

Prevention

When it happens

Trigger: Invalid or revoked BFL API key (401/403); wrong model name like `flux-pro-1.2-ultra` when the account lacks access (403/404); malformed request params - bad aspect_ratio, width/height not in allowed set (422); exceeding credits or rate limits (429); custom base_url missing the `/v1` prefix producing 404.

Common situations: New integration with an unset/expired BFL_API_KEY env var; copy-pasting a model id from BFL docs that the key's plan doesn't cover; passing width/height values BFL doesn't support; free-tier credit exhaustion during a demo; base_url configured without the correct path.

Related errors


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

Appendix: source

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

            litellm_params=litellm_params_dict,
            encoding=None,
        )

    def _poll_for_result_sync(
        self,
        initial_response: httpx.Response,
        headers: dict,
        sync_client: HTTPHandler,
        max_wait: float = DEFAULT_MAX_POLLING_TIME,
        interval: float = DEFAULT_POLLING_INTERVAL,
        timeout: float | httpx.Timeout | None = None,
    ) -> httpx.Response:
        """
        Poll BFL API until result is ready (sync version).
        """
        # Validate initial response status code
        if initial_response.status_code >= 400:
            raise BlackForestLabsError(
                status_code=initial_response.status_code,
                message=f"BFL initial request failed: {initial_response.text}",
            )

        # 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']}",

View on GitHub (pinned to 77b7c6c40c)