BerriAI/litellm · error · BlackForestLabsError
Error parsing BFL response
Error message
Error parsing BFL response: {e} What it means
After the BFL polling loop returns the final 'Ready' response, `transform_image_edit_response` calls `raw_response.json()` to extract `result.sample`. If that parse throws (body is not valid JSON), the error is wrapped in a `BlackForestLabsError` carrying the HTTP status code of the poll response. It means the final poll returned HTTP 200 with a non-JSON body, or a body encoding httpx cannot decode.
Solutions
- Retry the request once - a truncated/rewritten 200 body is usually transient.
- Capture `raw_response.text` (via your logging hook or verbose mode) to see what actually came back (HTML? empty? partial JSON?).
- If a proxy sits between you and BFL, bypass it or add it to the allowlist for the polling domain.
- If reproducible, check the BFL status page / API docs for response-format changes and update LiteLLM to the latest version in case the contract handling changed.
Defensive patterns
Strategy: retry
Try / catch
from litellm.llms.black_forest_labs.common_utils import BlackForestLabsError
try:
resp = litellm.image_edit(model="flux-kontext-pro", image=img, prompt=p)
except BlackForestLabsError as e:
if "Error parsing BFL response" in str(e):
resp = retry_with_backoff(lambda: litellm.image_edit(
model="flux-kontext-pro", image=img, prompt=p), attempts=2)
else:
raise Prevention
- Keep direct egress to the BFL polling domain; avoid rewriting proxies on that path.
- Enable litellm verbose logging so raw non-JSON bodies are observable when this fires.
- Wrap generation calls in a one-retry policy for parse-stage failures.
When it happens
Trigger: The BFL gateway (e.g. gateway.bfl.ai) returns an HTML error/landing page, empty body, or truncated gzip stream with status 200; a corporate proxy or middlebox rewrites the poll response; a flaky connection truncates the JSON mid-transfer so json() raises JSONDecodeError.
Common situations: Self-hosted or regional BFL endpoints behind an ingress that returns HTML on overload; TLS-terminating proxies that inject error pages; rare transient truncation. Very uncommon with the production api.bfl.ai/gateway.bfl.ai path - suspect infrastructure in between when you see it.
Understand the failure class
Background: "Invalid JSON response" and "Failed to parse response" errors: when an API answers 200 but the body isn't the JSON your library expected — this error's family across 28 libraries.
Related errors
- Error parsing initial response
- No image URL in BFL result
- Cisco AI Defense API returned a non-JSON response
- Max recursion depth reached while reading image bytes for…
- No polling_url in BFL response
AI-assisted analysis of BerriAI/litellm@77b7c6c40c (2026-08-18).
Data as JSON: /api/errors/1b2738ad577d6832.
Report an issue: GitHub.
Appendix: source
Thrown at litellm/llms/black_forest_labs/image_edit/transformation.py:297
# BFL uses JSON, not multipart - return empty files
return request_body, []
def transform_image_edit_response(
self,
model: str,
raw_response: httpx.Response,
logging_obj: LiteLLMLoggingObj,
) -> ImageResponse:
"""
Transform Black Forest Labs response to OpenAI-compatible ImageResponse.
This is called with the FINAL polled response (after handler does polling).
The response contains: {"status": "Ready", "result": {"sample": "https://..."}}
"""
try:
response_data: Final = raw_response.json()
except Exception as e:
raise BlackForestLabsError(
status_code=raw_response.status_code,
message=f"Error parsing BFL response: {e}",
)
# Get image URL from result
image_url: Final = response_data.get("result", {}).get("sample")
if not image_url:
raise BlackForestLabsError(
status_code=500,
message="No image URL in BFL result",
)
# Build ImageResponse
return ImageResponse(
created=int(time.time()),
data=[ImageObject(url=image_url)],
)
View on GitHub (pinned to 77b7c6c40c)