BerriAI/litellm · error · BlackForestLabsError
Polling timed out after {max_wait} seconds
Error message
Polling timed out after {max_wait} seconds What it means
The sync polling loop tracks elapsed time and raises 408 once `time.time() - start_time >= max_wait` without the job reaching a terminal status. The BFL job is likely still queued or processing — the client simply gave up first. No cancellation is sent upstream; the result may appear on BFL's side after you stopped asking.
Source
Thrown at litellm/llms/black_forest_labs/image_generation/handler.py:373
verbose_logger.debug("BFL poll status: %s", status)
if status == "Ready":
return response
elif status in [
"Error",
"Failed",
"Content Moderated",
"Request Moderated",
]:
raise BlackForestLabsError(
status_code=400,
message=f"Image generation failed: {status}",
)
time.sleep(interval)
raise BlackForestLabsError(
status_code=408,
message=f"Polling timed out after {max_wait} seconds",
)
async def _poll_for_result_async(
self,
initial_response: httpx.Response,
headers: dict,
async_client: AsyncHTTPHandler,
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 (async version).
"""
# Validate initial response status code
if initial_response.status_code >= 400:View on GitHub (pinned to 6c2dcb801b)
Solutions
- Raise the time budget: pass a larger timeout/max_wait via litellm_params or bump DEFAULT_MAX_POLLING_TIME in your fork/deployment.
- Lower concurrency per API key so jobs start sooner.
- Retry — resubmission after a timeout frequently completes faster than the stuck original.
- Pre-warm/tune prompt size and steps so jobs fit the window.
Example fix
# before img = litellm.image_generation(model="black_forest_labs/flux-pro-1.1", prompt="...") # after img = litellm.image_generation(model="black_forest_labs/flux-pro-1.1", prompt="...", timeout=600)
Defensive patterns
Strategy: retry
Validate before calling
null
Type guard
null
Try / catch
import time
for attempt in range(2):
try:
return litellm.image_generation(model=M, prompt=p, timeout=600)
except Exception as e:
if getattr(e, "status_code", None) == 408 and attempt == 0:
time.sleep(5)
continue
raise Prevention
- Pass timeout >= 600 for BFL generations; defaults are tight for heavy jobs.
- Limit per-key concurrency so jobs leave the queue quickly.
- Use aimage_generation in async stacks to avoid blocking a worker per poll loop.
When it happens
Trigger: litellm.image_generation (sync) where the job stays in non-terminal statuses (e.g. 'Processing', 'Queued') beyond DEFAULT_MAX_POLLING_TIME, with `time.sleep(interval)` between polls.
Common situations: Peak-load queueing on BFL; high-step or large generations; many concurrent jobs on one key; defaults tuned for lighter workloads.
Understand the failure class
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- Request failed: {e}
- No polling_url in BFL response
- Polling failed: {response.text}
- Image generation failed: {status}
- Task {task_id} did not complete within {max_attempts * poll_
AI-assisted analysis of BerriAI/litellm@6c2dcb801b (2026-08-15).
Data as JSON: /api/errors/1807616f72ffd114.
Report an issue: GitHub.