NovaKitv1.0

Error Handling

Implement robust error handling for production applications

Error Handling

Proper error handling is crucial for building reliable applications with the NovaKit API.

Error Types

StatusErrorAction
400Bad RequestFix request parameters
401UnauthorizedCheck API key
402Payment RequiredUpgrade plan or wait for reset
403ForbiddenCheck API key scopes
429Rate LimitedRetry with backoff
500Server ErrorRetry with backoff

Python Implementation

import requests
import time
from typing import Optional

class NovaKitError(Exception):
    """Base exception for NovaKit API errors."""
    def __init__(self, message: str, status_code: int, response: dict):
        super().__init__(message)
        self.status_code = status_code
        self.response = response

class AuthenticationError(NovaKitError):
    """API key is invalid or missing."""
    pass

class QuotaExceededError(NovaKitError):
    """Account quota has been exceeded."""
    pass

class RateLimitError(NovaKitError):
    """Rate limit has been exceeded."""
    def __init__(self, message: str, status_code: int, response: dict):
        super().__init__(message, status_code, response)
        self.retry_after = response.get("retry_after", 60)

class APIError(NovaKitError):
    """General API error."""
    pass


def make_request(
    endpoint: str,
    data: dict,
    max_retries: int = 3,
    base_delay: float = 1.0
) -> dict:
    """Make an API request with automatic retries."""

    for attempt in range(max_retries):
        try:
            response = requests.post(
                f"{BASE_URL}/{endpoint}",
                headers=headers,
                json=data,
                timeout=30
            )

            if response.status_code == 200:
                return response.json()

            error_data = response.json()
            error_message = error_data.get("error", "Unknown error")

            if response.status_code == 401:
                raise AuthenticationError(
                    error_message, response.status_code, error_data
                )

            if response.status_code == 402:
                raise QuotaExceededError(
                    error_message, response.status_code, error_data
                )

            if response.status_code == 429:
                error = RateLimitError(
                    error_message, response.status_code, error_data
                )
                if attempt < max_retries - 1:
                    time.sleep(error.retry_after)
                    continue
                raise error

            if response.status_code >= 500:
                if attempt < max_retries - 1:
                    delay = base_delay * (2 ** attempt)
                    time.sleep(delay)
                    continue
                raise APIError(
                    error_message, response.status_code, error_data
                )

            raise APIError(
                error_message, response.status_code, error_data
            )

        except requests.exceptions.Timeout:
            if attempt < max_retries - 1:
                time.sleep(base_delay * (2 ** attempt))
                continue
            raise

        except requests.exceptions.ConnectionError:
            if attempt < max_retries - 1:
                time.sleep(base_delay * (2 ** attempt))
                continue
            raise

    raise APIError("Max retries exceeded", 0, {})


# Usage
try:
    result = make_request(
        "chat/completions",
        {"messages": [{"role": "user", "content": "Hello"}]}
    )
    print(result["choices"][0]["message"]["content"])

except AuthenticationError as e:
    print(f"Auth failed: {e}. Check your API key.")

except QuotaExceededError as e:
    print(f"Quota exceeded: {e}. Upgrade your plan.")

except RateLimitError as e:
    print(f"Rate limited. Retry after {e.retry_after}s")

except APIError as e:
    print(f"API error ({e.status_code}): {e}")

TypeScript Implementation

class NovaKitError extends Error {
  constructor(
    message: string,
    public statusCode: number,
    public response: Record<string, any>
  ) {
    super(message);
    this.name = "NovaKitError";
  }
}

class RateLimitError extends NovaKitError {
  retryAfter: number;

  constructor(
    message: string,
    statusCode: number,
    response: Record<string, any>
  ) {
    super(message, statusCode, response);
    this.name = "RateLimitError";
    this.retryAfter = response.retry_after ?? 60;
  }
}

async function makeRequest(
  endpoint: string,
  data: object,
  maxRetries = 3
): Promise<any> {
  for (let attempt = 0; attempt < maxRetries; attempt++) {
    try {
      const response = await fetch(`${BASE_URL}/${endpoint}`, {
        method: "POST",
        headers,
        body: JSON.stringify(data),
      });

      if (response.ok) {
        return response.json();
      }

      const errorData = await response.json();

      if (response.status === 429) {
        const error = new RateLimitError(
          errorData.error,
          response.status,
          errorData
        );
        if (attempt < maxRetries - 1) {
          await sleep(error.retryAfter * 1000);
          continue;
        }
        throw error;
      }

      if (response.status >= 500 && attempt < maxRetries - 1) {
        await sleep(1000 * Math.pow(2, attempt));
        continue;
      }

      throw new NovaKitError(
        errorData.error,
        response.status,
        errorData
      );
    } catch (error) {
      if (error instanceof NovaKitError) throw error;
      if (attempt < maxRetries - 1) {
        await sleep(1000 * Math.pow(2, attempt));
        continue;
      }
      throw error;
    }
  }
}

const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms));

Best Practices

  1. Always implement retries for 429 and 5xx errors
  2. Use exponential backoff to avoid thundering herd
  3. Set timeouts to prevent hanging requests
  4. Log errors for debugging and monitoring
  5. Show user-friendly messages in your UI

On this page