abi/screenshot-to-code · error · Exception

Error taking screenshot

Error message

Error taking screenshot

What it means

Bare Exception("Error taking screenshot") raised inside capture_screenshot() when the screenshotone API returns a non-200 status or an empty body. The check `response.status_code == 200 and response.content` collapses every upstream failure mode — invalid/expired API key, quota exhaustion, blocked or unreachable target URL, upstream 5xx — into one opaque message with no status code or body attached.

Source

Thrown at backend/routes/screenshot.py:73

        "format": "png",
        "block_ads": "true",
        "block_cookie_banners": "true",
        "block_trackers": "true",
        "cache": "false",
        "viewport_width": "342",
        "viewport_height": "684",
    }

    if device == "desktop":
        params["viewport_width"] = "1280"
        params["viewport_height"] = "832"

    async with httpx.AsyncClient(timeout=60) as client:
        response = await client.get(api_base_url, params=params)
        if response.status_code == 200 and response.content:
            return response.content
        else:
            raise Exception("Error taking screenshot")


class ScreenshotRequest(BaseModel):
    url: str
    apiKey: str


class ScreenshotResponse(BaseModel):
    url: str


@router.post("/api/screenshot")
async def app_screenshot(request: ScreenshotRequest):
    # Extract the URL from the request body
    url = request.url
    api_key = request.apiKey

    try:

View on GitHub (pinned to d026163f58)

Solutions

  1. Verify the apiKey param passed to the endpoint is a valid, active screenshotone key
  2. Reproduce the upstream call manually with curl/httpx using the same params and inspect response.status_code and response.text to see the real error
  3. If quota/billing: check the screenshotone dashboard and top up or wait for reset
  4. Improve the raise to include status and body (see exampleFix) so future failures are diagnosable

Example fix

# before
if response.status_code == 200 and response.content:
    return response.content
else:
    raise Exception("Error taking screenshot")

# after
if response.status_code == 200 and response.content:
    return response.content
raise Exception(
    f"Screenshot API error: status={response.status_code} body={response.text[:200]}"
)
Defensive patterns

Strategy: retry

Validate before calling

def validate_screenshot_request(url: str, api_key: str) -> None:
    if not api_key or not api_key.strip():
        raise ValueError("apiKey is required for the screenshot service")
    if not is_screenshotable_url(url):
        raise ValueError(f"URL not screenshotable: {url}")

Try / catch

for attempt in range(2):
    try:
        return await capture_screenshot(url, api_key)
    except Exception as e:
        if str(e) == "Error taking screenshot" and attempt == 0:
            await asyncio.sleep(2); continue  # transient upstream failure, one retry
        raise

Prevention

When it happens

Trigger: GET to api_base_url (screenshotone) with params including url, apiKey, viewport dims returns 401/403 (bad key), 429 (quota), 402 (payment), or 200 with zero-length content (render failure of the target page).

Common situations: Expired screenshotone API key; free-tier quota used up; target page blocks headless crawlers or takes longer than the 60s httpx timeout handled elsewhere; api_base_url region endpoint misconfigured.

Related errors


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