abi/screenshot-to-code · error · ValueError

HTTP error occurred: {exc}

Error message

HTTP error occurred: {exc}

What it means

Wrapped error from _run_prediction: an httpx.HTTPStatusError (a 4xx/5xx HTTP response, surfaced by raise_for_status) is re-raised as ValueError with the exception text appended. The original status code, URL, and response are preserved via `from exc`. It fires for both the creation POST and every polling GET.

Source

Thrown at backend/image_generation/replicate.py:93

async def _run_prediction(
    endpoint_url: str, payload: dict[str, Any], api_token: str
) -> Any:
    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

View on GitHub (pinned to d026163f58)

Solutions

  1. Parse the embedded status: 401 → fix the token, 404 → fix model_path, 422 → fix input schema, 429 → back off.
  2. Inspect `exc.__cause__` (the HTTPStatusError) for the full response body with Replicate's detail message.
  3. Verify REPLICATE_API_KEY in backend/.env (this key only works via .env, not the UI settings).
  4. Add rate-limit backoff if firing under parallel requests.
Defensive patterns

Strategy: try-catch

Try / catch

try:
    output = await call_replicate_model(model, input, token)
except ValueError as e:
    cause = e.__cause__
    if isinstance(cause, httpx.HTTPStatusError):
        status = cause.response.status_code
        if status == 401:
            return error("Invalid Replicate API token")
        if status == 404:
            return error(f"Unknown model: {model}")
        if status == 429:
            await asyncio.sleep(backoff); retry = True
    raise

Prevention

When it happens

Trigger: 401 invalid REPLICATE_API_KEY; 404 unknown model_path; 422 invalid input payload for the model; 429 rate limited. The exc text embeds the status code and server message, e.g. "Client error '401 Unauthorized' for url ...".

Common situations: Expired or mistyped API token; using a model name that was renamed or deleted; exceeding Replicate rate limits under concurrent generation; malformed input JSON the API rejects.

Related errors


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