Error Reference #
Complete guide to Nellie API error codes and how to handle them.
Error Response Format #
All API errors follow a consistent JSON format:
{
"success": false,
"error": "Human-readable error message",
"details": "Additional context (optional)",
"errorCode": "MACHINE_READABLE_CODE"
}
| Field | Type | Description |
|---|---|---|
success |
boolean | Always false for errors |
error |
string | Human-readable error message |
details |
string | Additional context (optional) |
errorCode |
string | Machine-readable code for programmatic handling |
HTTP Status Codes #
400 Bad Request #
Invalid request parameters or malformed request body.
INVALID_PARAMETER #
{
"success": false,
"error": "Field 'style' must be one of: action, adventure, automatic, ...",
"errorCode": "INVALID_PARAMETER"
}
Causes:
- Invalid value for
style,type,model, oroutput_format - Invalid data type (e.g., string where boolean expected)
Solution:
# Check valid values before submitting
config = client.get_configuration()
if style not in config.styles:
raise ValueError(f"Invalid style. Valid options: {config.styles}")
INVALID_WEBHOOK_URL #
{
"success": false,
"error": "Invalid webhook URL: must be a valid HTTPS URL",
"errorCode": "INVALID_WEBHOOK_URL"
}
Causes:
- URL is not HTTPS
- URL is localhost or internal IP
- URL is malformed
Solution:
# Ensure webhook URL is valid
import re
def is_valid_webhook_url(url):
if not url.startswith("https://"):
return False
if "localhost" in url or "127.0.0.1" in url:
return False
return True
MISSING_PARAMETER #
{
"success": false,
"error": "Missing required field: prompt",
"errorCode": "MISSING_PARAMETER"
}
Note: Currently all parameters are optional, but this error may appear in future API versions.
401 Unauthorized #
Authentication failed.
AUTH_REQUIRED #
{
"success": false,
"error": "Unauthorized",
"details": "Valid API key required",
"errorCode": "AUTH_REQUIRED"
}
Causes:
- Missing
X-API-Keyheader - Empty API key value
Solution:
# Ensure header is present
headers = {
"X-API-Key": os.environ.get("NELLIE_API_KEY"),
"Content-Type": "application/json"
}
if not headers["X-API-Key"]:
raise ValueError("NELLIE_API_KEY environment variable not set")
AUTH_FAILED #
{
"success": false,
"error": "Invalid API key",
"errorCode": "AUTH_FAILED"
}
Causes:
- API key is invalid
- API key has been revoked
- API key is malformed
Solution:
# Verify key format
if not api_key.startswith("nel_"):
raise ValueError("Invalid API key format")
# Test authentication
try:
client.get_usage()
except AuthenticationError:
print("API key is invalid or revoked. Create a new key in the dashboard.")
403 Forbidden #
Permission denied.
FORBIDDEN #
{
"success": false,
"error": "Access denied",
"errorCode": "FORBIDDEN"
}
Causes:
- Attempting to access another user’s resource
- API key lacks required permissions
- Verify you’re using the correct API key
- Check that the request ID belongs to your account
Solution:
404 Not Found #
Resource not found.
NOT_FOUND #
{
"success": false,
"error": "Request not found",
"errorCode": "NOT_FOUND"
}
Causes:
- Invalid
requestIdin status endpoint - Request was deleted or never existed
Solution:
# Validate request ID format (UUID)
import uuid
def is_valid_request_id(request_id):
try:
uuid.UUID(request_id)
return True
except ValueError:
return False
if not is_valid_request_id(request_id):
raise ValueError("Invalid request ID format")
405 Method Not Allowed #
Wrong HTTP method for endpoint.
METHOD_NOT_ALLOWED #
{
"success": false,
"error": "Method not allowed",
"errorCode": "METHOD_NOT_ALLOWED"
}
Causes:
- Using GET instead of POST for
/v1/book - Using POST instead of GET for
/v1/status
Solution:
# Correct methods:
# POST /v1/book - Create book
# GET /v1/status/{id} - Check status
# GET /v1/configuration - Get config
# GET /v1/models - Get models
# GET /v1/usage - Get usage (requires auth)
429 Too Many Requests #
Rate limit exceeded.
RATE_LIMIT_EXCEEDED (Burst) #
{
"success": false,
"error": "Rate limit exceeded: Please wait a few seconds between requests",
"errorCode": "RATE_LIMIT_EXCEEDED"
}
Causes:
- Requests sent faster than 1 per 6 seconds
Solution:
import time
from nellie_api import RateLimitError
def create_with_backoff(prompt, max_retries=3):
for attempt in range(max_retries):
try:
return client.books.create(prompt=prompt)
except RateLimitError:
wait_time = 6 * (attempt + 1)
print(f"Rate limited. Waiting {wait_time}s...")
time.sleep(wait_time)
raise Exception("Max retries exceeded")
RATE_LIMIT_EXCEEDED (Daily) #
{
"success": false,
"error": "Daily rate limit exceeded (15 requests/day)",
"errorCode": "RATE_LIMIT_EXCEEDED"
}
Causes:
- Exceeded 15 requests in 24 hours
Solution:
# Check remaining daily quota
usage = client.get_usage()
if usage.total_requests >= 15:
print("Daily limit reached. Try again tomorrow.")
500 Internal Server Error #
Server-side error.
INTERNAL_ERROR #
{
"success": false,
"error": "Internal server error",
"errorCode": "INTERNAL_ERROR"
}
Causes:
- Temporary server issue
- Unexpected error during processing
Solution:
# Implement retry with exponential backoff
import time
def retry_on_server_error(func, max_retries=3):
for attempt in range(max_retries):
try:
return func()
except APIError as e:
if e.status_code >= 500:
wait_time = 2 ** attempt * 10
print(f"Server error. Retrying in {wait_time}s...")
time.sleep(wait_time)
else:
raise
raise Exception("Max retries exceeded")
JOB_START_FAILED #
{
"success": false,
"error": "Failed to start generation job",
"errorCode": "JOB_START_FAILED"
}
Causes:
- Backend queue unavailable
- Resource constraints
- Wait a few minutes and retry
- Contact support if persistent
Solution:
503 Service Unavailable #
Service temporarily unavailable.
{
"success": false,
"error": "Service temporarily unavailable",
"errorCode": "SERVICE_UNAVAILABLE"
}
Causes:
- Planned maintenance
- High load
- Infrastructure issues
- Wait and retry with exponential backoff
- Check status page for announcements
Solution:
Job Status Errors #
When checking status, errors appear in the response body:
Insufficient Credits #
{
"requestId": "uuid",
"status": "failed",
"progress": 0,
"error": "Insufficient credits",
"errorMessage": "Insufficient credits"
}
Solution:
# Pre-check credits before starting
usage = client.get_usage()
models = client.get_models()
required = next(m.cost_per_book for m in models if m.id == "3.0")
available = CREDIT_LIMIT - usage.total_credits_used
if available < required:
print(f"Need {required} credits, have {available}")
Generation Error #
{
"requestId": "uuid",
"status": "failed",
"progress": 45,
"error": "Generation failed: content policy violation"
}
Causes:
- Prompt violated content policy
- Generation encountered unexpected error
- Review and modify your prompt
- Contact support with the request ID
Solution:
SDK Exceptions #
The Python SDK raises typed exceptions:
Exception Hierarchy #
NellieError (base)
├── AuthenticationError (401)
├── RateLimitError (429)
└── APIError (other errors)
Handling Exceptions #
from nellie_api import (
Nellie,
NellieError,
AuthenticationError,
RateLimitError,
APIError
)
try:
client = Nellie()
book = client.books.create(prompt="...")
except AuthenticationError as e:
# Invalid or missing API key
print(f"Auth error: {e}")
print(f"Status code: {e.status_code}") # 401
except RateLimitError as e:
# Too many requests
print(f"Rate limited: {e}")
print(f"Status code: {e.status_code}") # 429
except APIError as e:
# Other API errors
print(f"API error: {e}")
print(f"Status code: {e.status_code}")
print(f"Response body: {e.body}")
except NellieError as e:
# Catch-all for SDK errors
print(f"Nellie error: {e}")
WebhookSignatureError #
from nellie_api import Webhook, WebhookSignatureError
try:
event = Webhook.construct_event(payload, sig_header, secret)
except WebhookSignatureError:
# Invalid signature
return "Invalid signature", 400
Error Handling Patterns #
Comprehensive Handler #
from nellie_api import (
Nellie,
AuthenticationError,
RateLimitError,
APIError,
NellieError
)
import time
import logging
logger = logging.getLogger(__name__)
def safe_generate(prompt: str, max_retries: int = 3) -> dict:
""Generate a book with comprehensive error handling.""
for attempt in range(max_retries):
try:
client = Nellie()
book = client.books.create(prompt=prompt)
return {
"success": True,
"request_id": book.request_id
}
except AuthenticationError as e:
logger.error(f"Authentication failed: {e}")
return {
"success": False,
"error_code": "AUTH_ERROR",
"message": "Invalid API key. Please check your configuration.",
"retryable": False
}
except RateLimitError as e:
wait_time = 10 * (attempt + 1)
logger.warning(f"Rate limited. Waiting {wait_time}s...")
time.sleep(wait_time)
continue # Retry
except APIError as e:
if e.status_code >= 500:
# Server error - retry
wait_time = 5 * (attempt + 1)
logger.warning(f"Server error ({e.status_code}). Retrying in {wait_time}s...")
time.sleep(wait_time)
continue
else:
# Client error - don't retry
logger.error(f"API error: {e}")
return {
"success": False,
"error_code": "API_ERROR",
"message": str(e),
"status_code": e.status_code,
"retryable": False
}
except NellieError as e:
logger.exception(f"Unexpected error: {e}")
return {
"success": False,
"error_code": "UNKNOWN_ERROR",
"message": str(e),
"retryable": False
}
# Max retries exceeded
return {
"success": False,
"error_code": "MAX_RETRIES",
"message": "Request failed after multiple attempts",
"retryable": True
}
User-Friendly Error Messages #
ERROR_MESSAGES = {
"AUTH_REQUIRED": "Please log in to continue.",
"AUTH_FAILED": "Your session has expired. Please log in again.",
"RATE_LIMIT_EXCEEDED": "You're making requests too quickly. Please wait a moment.",
"INVALID_PARAMETER": "Some of your inputs are invalid. Please check and try again.",
"INSUFFICIENT_CREDITS": "You don't have enough credits. Please purchase more.",
"NOT_FOUND": "The requested book could not be found.",
"INTERNAL_ERROR": "Something went wrong on our end. Please try again later.",
}
def get_user_message(error_code: str, default: str = "An error occurred.") -> str:
return ERROR_MESSAGES.get(error_code, default)
Troubleshooting Guide #
| Error | Check | Solution |
|---|---|---|
| 401 AUTH_REQUIRED | Is X-API-Key header present? |
Add header to request |
| 401 AUTH_FAILED | Is key valid? | Create new key in dashboard |
| 429 RATE_LIMIT | Requests too fast? | Add delays between requests |
| 429 RATE_LIMIT | Daily limit reached? | Wait 24 hours or contact sales |
| 400 INVALID_PARAMETER | Check parameter values | Use /v1/configuration to get valid values |
| 404 NOT_FOUND | Valid request ID? | Verify the ID was returned by /v1/book |
| 500 INTERNAL_ERROR | Temporary issue? | Retry with exponential backoff |
| Job failed: Insufficient credits | Check credit balance | Purchase more credits |
Related Documentation #
- Rate Limits -- Understanding rate limiting
- Troubleshooting -- Step-by-step debugging
- Authentication -- API key management
- SDK Reference -- Exception handling in the SDK