abi/screenshot-to-code · error · HTTPException
Error capturing screenshot: {str(e)}
Error message
Error capturing screenshot: {str(e)} What it means
Catch-all HTTPException(500, f"Error capturing screenshot: {e}") raised by /api/screenshot for any failure that is not a ValueError. In practice this wraps the generic "Error taking screenshot" Exception from capture_screenshot (screenshotone API non-200/empty) and httpx transport errors (DNS failure, connection refused, 60s timeout). The detail string echoes the original exception message, so its content tells you which layer failed.
Source
Thrown at backend/routes/screenshot.py:107
api_key = request.apiKey
try:
# Normalize the URL
normalized_url = normalize_url(url)
# Capture screenshot with normalized URL
image_bytes = await capture_screenshot(normalized_url, api_key=api_key)
# Convert the image bytes to a data url
data_url = bytes_to_data_url(image_bytes, "image/png")
return ScreenshotResponse(url=data_url)
except ValueError as e:
# Handle URL normalization errors
raise HTTPException(status_code=500, detail=str(e))
except Exception as e:
# Handle other errors
raise HTTPException(status_code=500, detail=f"Error capturing screenshot: {str(e)}")
View on GitHub (pinned to d026163f58)
Solutions
- Read the detail substring: 'Error taking screenshot' means upstream rejected the request — validate the apiKey and quota (see error 84)
- If the detail names httpx.ConnectError/ConnectTimeout: check outbound network/DNS from the backend host
- If httpx.ReadTimeout: retry once, or raise the httpx timeout in capture_screenshot beyond 60s
- Reproduce with the same URL from a working environment to isolate target-specific blocking
Example fix
# before
resp = await client.post("/api/screenshot", json=req)
if resp.status_code >= 400:
raise RuntimeError(resp.text) # loses cause
# after (structured handling)
try:
resp = await client.post("/api/screenshot", json=req)
resp.raise_for_status()
except httpx.HTTPStatusError:
detail = resp.json().get("detail", "")
if "Unsupported protocol" in detail:
raise ValueError(f"Bad URL: {url}")
raise RuntimeError(f"Screenshot failed: {detail}") Defensive patterns
Strategy: try-catch
Validate before calling
def preflight(url: str, api_key: str) -> None:
validate_screenshot_request(url, api_key) # catches scheme/key issues client-side
socket.create_connection((urlparse(url).hostname, 443), timeout=5).close() # egress check Try / catch
try:
shot = await take_screenshot(url)
except httpx.HTTPStatusError as e:
detail = e.response.json().get("detail", "")
if "Error taking screenshot" in detail:
handle_upstream_failure(detail) # key/quota/target issue
elif "timeout" in detail.lower():
return await retry_with_backoff(take_screenshot, url) # transient
else:
handle_network_failure(detail) Prevention
- Branch on the detail substring to separate upstream, network, and timeout causes
- Retry only timeout/network failures; upstream auth failures need human action
- Health-check outbound egress and the screenshotone key as part of app startup checks
When it happens
Trigger: POST /api/screenshot where the screenshotone call fails upstream (bad key, quota — detail contains 'Error taking screenshot') or the HTTP request itself fails (detail contains httpx.ConnectError/ReadTimeout); also bytes_to_data_url failures, though those are unlikely.
Common situations: No outbound network access from the backend container; screenshotone key invalid; target host unreachable; slow page exceeding the 60-second httpx timeout.
Related errors
- Design systems storage is not valid JSON
- Design systems storage must contain a list
- Error reading input files: {str(e)}
- Error processing evals: {str(e)}
- Error reading output folders: {str(e)}
AI-assisted analysis of abi/screenshot-to-code@d026163f58 (2026-08-14).
Data as JSON: /api/errors/019e8807d157a035.
Report an issue: GitHub.