Skip to main content

Error Handling

The API uses standard HTTP status codes and returns detailed error information.

Error Response Format

{
"error": {
"code": "VALIDATION_ERROR",
"message": "Human-readable error message",
"details": {
"field": "title",
"reason": "required"
}
}
}

HTTP Status Codes

CodeDescription
400Bad Request - Invalid parameters
401Unauthorized - Invalid or missing API key
403Forbidden - Insufficient permissions
404Not Found - Resource doesn't exist
409Conflict - Resource already exists
422Unprocessable Entity - Validation error
429Too Many Requests - Rate limit exceeded
500Internal Server Error - Something went wrong

Error Codes

Authentication Errors

CodeHTTPDescription
UNAUTHORIZED401API key is invalid or expired
FORBIDDEN403User lacks permission for this action
TOKEN_EXPIRED401OAuth token has expired

Validation Errors

CodeHTTPDescription
VALIDATION_ERROR422Request body failed validation
INVALID_PARAMETER400Query parameter is invalid
MISSING_REQUIRED400Required field is missing

Resource Errors

CodeHTTPDescription
NOT_FOUND404Resource doesn't exist
ALREADY_EXISTS409Resource with same identifier exists
DELETED410Resource has been deleted

Rate Limiting

CodeHTTPDescription
RATE_LIMITED429Too many requests
QUOTA_EXCEEDED429Daily quota exceeded

Server Errors

CodeHTTPDescription
INTERNAL_ERROR500Unexpected server error
SERVICE_UNAVAILABLE503Service temporarily unavailable

Handling Errors

TypeScript SDK

import { RavenDocs, RavenDocsError } from '@raven-docs/sdk';

const client = new RavenDocs({ apiKey: '...' });

try {
const page = await client.pages.get({ pageId: 'invalid' });
} catch (error) {
if (error instanceof RavenDocsError) {
console.log('Code:', error.code);
console.log('Message:', error.message);
console.log('Status:', error.status);

if (error.code === 'NOT_FOUND') {
// Handle missing page
} else if (error.code === 'FORBIDDEN') {
// Handle permission error
}
}
}

REST API

response=$(curl -s -w "\n%{http_code}" \
http://localhost:3000/api/pages/invalid \
-H "Authorization: Bearer $API_KEY")

status=$(echo "$response" | tail -n1)
body=$(echo "$response" | sed '$d')

if [ "$status" != "200" ]; then
echo "Error: $(echo $body | jq -r '.error.message')"
fi

Retry Strategy

For transient errors, implement exponential backoff:

async function fetchWithRetry(fn: () => Promise<any>, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
return await fn();
} catch (error) {
if (error.status === 429 || error.status >= 500) {
// Retry with exponential backoff
const delay = Math.pow(2, i) * 1000;
await new Promise((r) => setTimeout(r, delay));
continue;
}
throw error;
}
}
throw new Error('Max retries exceeded');
}

Retry Headers

Rate limit responses include helpful headers:

HeaderDescription
X-RateLimit-LimitMax requests per window
X-RateLimit-RemainingRequests left in window
X-RateLimit-ResetUnix timestamp when window resets
Retry-AfterSeconds to wait before retrying

Debugging

Enable Verbose Logging

const client = new RavenDocs({
apiKey: '...',
debug: true, // Logs all requests and responses
});

Request IDs

Every response includes a request ID for support:

X-Request-Id: req_abc123xyz

Include this when contacting support.