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
- Log the full submission JSON on failure to see which schema actually arrived.
- Confirm api_base targets the official BFL endpoint or a fully schema-compatible one.
- Upgrade LiteLLM — newer releases track BFL schema changes.
- 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
- Freeze api_base to the official endpoint unless you own the alternative's schema.
- Upgrade LiteLLM together with BFL API announcements.
- Add a canary request after deploying new api_base configs.
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
- No image URL in BFL result
- Error parsing initial response: {e}
- Polling failed: {response.text}
- Image generation failed: {status}
- Polling timed out after {max_wait} seconds
AI-assisted analysis of BerriAI/litellm@6c2dcb801b (2026-08-15).
Data as JSON: /api/errors/8da8bce1e40a6d37.
Report an issue: GitHub.