abi/screenshot-to-code · error · TimeoutError

Request timed out

Error message

Request timed out

What it means

Raised when asyncio.TimeoutError escapes the try block in _run_prediction and is converted to the builtin TimeoutError. In practice this is the socket-level timeout path (httpx default timeouts) rather than the poll-budget exhaustion, which raises TimeoutError("Inference timed out") directly and passes through the (TimeoutError, ValueError) re-raise untouched. Note the bare TimeoutError("Request timed out") message distinguishes the two.

Source

Thrown at backend/image_generation/replicate.py:97

    headers = _build_headers(api_token)

    async with httpx.AsyncClient() as client:
        try:
            response = await client.post(endpoint_url, headers=headers, json=payload)
            response.raise_for_status()
            response_json = response.json()
            if not isinstance(response_json, dict):
                raise ValueError("Invalid prediction creation response.")

            prediction_id = _extract_prediction_id(response_json)
            final_response = await _poll_prediction(client, prediction_id, headers)
            return final_response.get("output")
        except httpx.HTTPStatusError as exc:
            raise ValueError(f"HTTP error occurred: {exc}") from exc
        except httpx.RequestError as exc:
            raise ValueError(f"An error occurred while requesting: {exc}") from exc
        except asyncio.TimeoutError as exc:
            raise TimeoutError("Request timed out") from exc
        except (TimeoutError, ValueError):
            raise
        except Exception as exc:
            raise ValueError(f"An unexpected error occurred: {exc}") from exc


def _extract_output_url(result: Any, context: str) -> str:
    if isinstance(result, str):
        return result

    if isinstance(result, dict):
        url = cast(Any, result.get("url"))
        if isinstance(url, str) and url:
            return url

    if isinstance(result, list) and len(result) > 0:
        first = cast(Any, result[0])
        if isinstance(first, str) and first:

View on GitHub (pinned to d026163f58)

Solutions

  1. Distinguish from "Inference timed out": this one is a single-request timeout, not poll-budget exhaustion.
  2. Pass an explicit larger timeout when constructing httpx.AsyncClient (e.g. httpx.Timeout(60.0)).
  3. Retry the operation — single-request timeouts are typically transient.
  4. Avoid blocking the event loop with sync work during generation.

Example fix

# before
async with httpx.AsyncClient() as client:

# after
async with httpx.AsyncClient(timeout=httpx.Timeout(60.0, connect=10.0)) as client:
Defensive patterns

Strategy: retry

Try / catch

try:
    output = await call_replicate_model(model, input, token)
except TimeoutError as e:
    if str(e) == "Request timed out":
        # single-request timeout: safe to retry immediately
        output = await call_replicate_model(model, input, token)
    raise

Prevention

When it happens

Trigger: An httpx operation exceeding its default timeout during the creation POST or a polling GET and surfacing as asyncio.TimeoutError; on some event-loop/HTTP combinations a CancelledError-adjacent timeout during a long poll.

Common situations: Slow mobile/tethered connections where individual HTTP round-trips exceed httpx defaults; overloaded Replicate endpoints making even status GETs slow; event loop stalls from CPU-heavy work in the same process delaying async I/O.

Understand the failure class

Related errors


AI-assisted analysis of abi/screenshot-to-code@d026163f58 (2026-08-14). Data as JSON: /api/errors/c1b365a5b47d8e0b. Report an issue: GitHub.