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
| Status | Error | Action |
|---|---|---|
| 400 | Bad Request | Fix request parameters |
| 401 | Unauthorized | Check API key |
| 402 | Payment Required | Upgrade plan or wait for reset |
| 403 | Forbidden | Check API key scopes |
| 429 | Rate Limited | Retry with backoff |
| 500 | Server Error | Retry 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
- Always implement retries for 429 and 5xx errors
- Use exponential backoff to avoid thundering herd
- Set timeouts to prevent hanging requests
- Log errors for debugging and monitoring
- Show user-friendly messages in your UI