# How Screenshot-to-Code Handles API Authentication Errors and Rate Limits

> Learn how screenshot-to-code manages API authentication errors and rate limits. Discover centralized error handling and user-friendly messages for a seamless experience.

- Repository: [Abi Raja/screenshot-to-code](https://github.com/abi/screenshot-to-code)
- Tags: internals
- Published: 2026-03-02

---

**The backend catches OpenAI SDK exceptions in a centralized try-except block and transmits user-friendly error messages via WebSocket, allowing the UI to display guidance while keeping the connection alive.**

The `abi/screenshot-to-code` repository implements a resilient error-handling strategy for its AI-powered code generation pipeline. When the system encounters **API authentication failures** or **rate limits** from OpenAI, it isolates the error to the specific generation variant and returns actionable feedback to the frontend without crashing the service.

## Error Handling Architecture in the Generation Pipeline

The generation logic resides in [`backend/routes/generate_code.py`](https://github.com/abi/screenshot-to-code/blob/main/backend/routes/generate_code.py), where each code generation request spawns an **Agent** for every variant requested. The execution wraps the runner inside a `try … except` block that specifically targets OpenAI SDK exception types.

### The CodeGenerationMiddleware Process Method

According to the source code, the `CodeGenerationMiddleware` class contains the `process` method that orchestrates the LLM calls. When the OpenAI client raises an exception, the middleware intercepts it before it can propagate to the WebSocket handler, ensuring the connection remains stable for other concurrent variants.

### Exception Isolation per Variant

The system handles errors at the variant level. If one generation thread encounters an authentication failure, the backend returns an empty string for that specific variant only, allowing other valid variants to continue processing. This granular approach prevents a single bad API key or exhausted quota from terminating the entire session.

## Specific Error Types and Responses

The code distinguishes between three specific OpenAI error classes, each triggering a tailored user message and logging output.

### AuthenticationError Handling

When the SDK raises `openai.AuthenticationError`, the backend logs the failure with the variant index and constructs a detailed hint. The error message explicitly states that the API key is incorrect and directs users to the OpenAI dashboard, with an additional prompt to purchase credits if running in production mode (`IS_PROD`).

```python

# backend/routes/generate_code.py – error handling (excerpt)

try:
    completion = await runner.run(model, prompt_messages)
    # … send success messages …

except openai.AuthenticationError as e:
    print(f"[VARIANT {index + 1}] OpenAI Authentication failed", e)
    error_message = (
        "Incorrect OpenAI key. Please make sure your OpenAI API key is correct, "
        "or create a new OpenAI API key on your OpenAI dashboard."
        + (" Alternatively, you can purchase code generation credits directly on this website."
           if IS_PROD else "")
    )
    await self.send_message("variantError", error_message, index, None, None)
    return ""

```

### RateLimitError Handling

For quota exhaustion signaled by `openai.RateLimitError`, the system emits a similar `variantError` event. The message quotes the official OpenAI explanation regarding billing and plan details, again offering the in-app purchase option when `IS_PROD` is enabled.

```python
except openai.RateLimitError as e:
    print(f"[VARIANT {index + 1}] OpenAI Rate limit exceeded", e)
    error_message = (
        "OpenAI error - 'You exceeded your current quota, please check your plan and billing details.'"
        + (" Alternatively, you can purchase code generation credits directly on this website."
           if IS_PROD else "")
    )
    await self.send_message("variantError", error_message, index, None, None)
    return ""

```

### NotFoundError for Missing Models

The pipeline also catches `openai.NotFoundError` separately to inform users when a requested model (such as `gpt-4-vision-preview`) is unavailable or deprecated, ensuring users understand when a model string needs updating.

## Frontend Communication via WebSocket

All error messages transmit through the `send_message` method as `variantError` events. The frontend component at [`frontend/src/lib/utils.ts`](https://github.com/abi/screenshot-to-code/blob/main/frontend/src/lib/utils.ts) parses these WebSocket payloads and renders them as alerts, enabling real-time user notification without page refreshes. The backend explicitly avoids closing the connection, maintaining the session state for potential retries or alternative key submissions.

## Code Example: Simulating Authentication Failures

While the actual error originates from the OpenAI SDK, the following snippet demonstrates the exception structure and handling pattern found in the pipeline.

```python
from openai import OpenAI, AuthenticationError

client = OpenAI(api_key="invalid-key")

try:
    # Any API call that requires authentication will raise AuthenticationError

    client.chat.completions.create(
        model="gpt-4-vision-preview",
        messages=[{"role": "user", "content": "test"}],
    )
except AuthenticationError as e:
    # Mimic the generation‑pipeline handling

    error_message = (
        "Incorrect OpenAI key. Please make sure your OpenAI API key is correct."
    )
    # In the actual pipeline this is sent via WebSocket:

    # await websocket.send_json({"type": "variantError", "message": error_message})

    print("variantError →", error_message)

```

## Summary

- The [`backend/routes/generate_code.py`](https://github.com/abi/screenshot-to-code/blob/main/backend/routes/generate_code.py) file contains the primary error handling logic in lines 599-638, catching `AuthenticationError`, `RateLimitError`, and `NotFoundError`.
- Errors are isolated per variant using a `try … except` block in the `CodeGenerationMiddleware`, returning empty strings to stop only the affected pipeline branch.
- User-facing messages are transmitted via `variantError` WebSocket events, providing specific guidance on fixing API keys or upgrading billing plans.
- The system remains resilient by keeping the WebSocket connection alive, allowing users to correct credentials and retry without restarting the application.

## Frequently Asked Questions

### What happens to other generation variants if one encounters an API error?

The error handling is scoped to individual variants. When an exception occurs, the backend returns an empty string for that specific variant only, allowing other concurrent generation threads to complete successfully. This prevents a single invalid API key from blocking all output variations.

### Where are the error messages defined in the codebase?

The error strings reside directly in the exception handlers within [`backend/routes/generate_code.py`](https://github.com/abi/screenshot-to-code/blob/main/backend/routes/generate_code.py). The messages include conditional logic based on the `IS_PROD` environment variable to optionally append purchase credit links when running in production environments.

### How does the frontend receive and display these errors?

The backend sends `variantError` events through the persistent WebSocket connection established during session initialization. The frontend utilities in [`frontend/src/lib/utils.ts`](https://github.com/abi/screenshot-to-code/blob/main/frontend/src/lib/utils.ts) listen for these events and surface them as user notifications, typically displaying the specific error guidance in the generation interface.

### Does the application crash when hitting a rate limit?

No, the application explicitly catches `openai.RateLimitError` and converts it into a user-friendly message without raising the exception further. The WebSocket connection remains open, and the backend logs the incident for monitoring purposes while allowing the user to address their OpenAI billing settings.