Error Handling
Understanding and handling errors from the Check API.
Error Handling
The Check API uses conventional HTTP status codes and returns detailed error information to help you handle issues gracefully.
Error Response Format
All errors return a consistent JSON structure:
{
"error": {
"code": "error_code",
"message": "Human-readable error message",
"details": [
{
"field": "content",
"message": "Field-specific error message"
}
],
"requestId": "req_abc123"
}
}Error Fields
| Field | Description |
|---|---|
code | Machine-readable error code for programmatic handling |
message | Human-readable description of the error |
details | Array of field-specific errors (for validation errors) |
requestId | Unique identifier for this request (useful for support) |
HTTP Status Codes
Success Codes (2xx)
| Status | Description |
|---|---|
| 200 | Success - Request completed successfully |
| 201 | Created - Resource created successfully |
| 202 | Accepted - Request accepted for async processing |
Client Errors (4xx)
| Status | Code | Description |
|---|---|---|
| 400 | bad_request | Invalid request format or parameters |
| 401 | unauthorized | Missing or invalid API key |
| 403 | forbidden | Valid key but insufficient permissions |
| 404 | not_found | Resource doesn't exist |
| 409 | conflict | Resource already exists or state conflict |
| 422 | validation_error | Request validation failed |
| 429 | rate_limited | Too many requests |
Server Errors (5xx)
| Status | Code | Description |
|---|---|---|
| 500 | internal_error | Unexpected server error |
| 502 | bad_gateway | Upstream service error (LLM provider) |
| 503 | service_unavailable | Temporary maintenance or overload |
| 504 | gateway_timeout | Upstream service timeout |
Common Error Codes
Authentication Errors
401 - Missing API Key
{
"error": {
"code": "unauthorized",
"message": "API key is required. Include it in the Authorization header as 'Bearer vfy_...'",
"requestId": "req_abc123"
}
}401 - Invalid API Key
{
"error": {
"code": "unauthorized",
"message": "Invalid API key. Check that your key is correct and active.",
"requestId": "req_abc123"
}
}401 - Expired API Key
{
"error": {
"code": "unauthorized",
"message": "API key has been revoked. Generate a new key from your dashboard.",
"requestId": "req_abc123"
}
}Validation Errors
400 - Missing Required Field
{
"error": {
"code": "validation_error",
"message": "Validation failed",
"details": [
{
"field": "content",
"message": "Content is required"
}
],
"requestId": "req_abc123"
}
}400 - Invalid Field Value
{
"error": {
"code": "validation_error",
"message": "Validation failed",
"details": [
{
"field": "methods.reasoning",
"message": "Method weight must be between 0 and 1"
}
],
"requestId": "req_abc123"
}
}400 - Content Too Long
{
"error": {
"code": "validation_error",
"message": "Validation failed",
"details": [
{
"field": "content",
"message": "Content exceeds maximum length of 50,000 characters"
}
],
"requestId": "req_abc123"
}
}Rate Limiting
429 - Rate Limited
{
"error": {
"code": "rate_limited",
"message": "Rate limit exceeded. Try again in 60 seconds.",
"retryAfter": 60,
"requestId": "req_abc123"
}
}Usage Limits
403 - Monthly Limit Reached
{
"error": {
"code": "usage_limit_exceeded",
"message": "Monthly verification limit reached. Upgrade your plan for more verifications.",
"limit": 1000,
"used": 1000,
"resetDate": "2024-02-01T00:00:00Z",
"requestId": "req_abc123"
}
}Resource Errors
404 - Verification Not Found
{
"error": {
"code": "not_found",
"message": "Verification ver_abc123 not found",
"requestId": "req_abc123"
}
}404 - Batch Not Found
{
"error": {
"code": "not_found",
"message": "Batch batch_abc123 not found or you don't have access to it",
"requestId": "req_abc123"
}
}Provider Errors
502 - LLM Provider Error
{
"error": {
"code": "provider_error",
"message": "The LLM provider returned an error. This is usually temporary.",
"provider": "openai",
"providerError": "Rate limit exceeded",
"requestId": "req_abc123"
}
}504 - Provider Timeout
{
"error": {
"code": "provider_timeout",
"message": "The LLM provider took too long to respond. Please retry.",
"provider": "anthropic",
"requestId": "req_abc123"
}
}Handling Errors
TypeScript SDK
The SDK provides typed error classes for easy handling:
import {
Check,
CheckError,
AuthenticationError,
ValidationError,
RateLimitError,
QuotaExceededError,
NotFoundError,
ProviderError,
} from '@check/sdk';
const client = new Check({ apiKey: 'vfy_...' });
try {
const result = await client.verifyAndWait({
content: 'Your content',
methods: { reasoning: 1.0 }
});
} catch (error) {
if (error instanceof AuthenticationError) {
// Invalid or missing API key
console.error('Authentication failed:', error.message);
// Redirect to login or show API key configuration
} else if (error instanceof ValidationError) {
// Invalid request parameters
console.error('Validation failed:', error.message);
for (const detail of error.details) {
console.error(` ${detail.field}: ${detail.message}`);
}
} else if (error instanceof RateLimitError) {
// Rate limited - wait and retry
console.error(`Rate limited. Retry after ${error.retryAfter}s`);
await sleep(error.retryAfter * 1000);
// Retry the request
} else if (error instanceof QuotaExceededError) {
// Monthly quota exceeded
console.error('Monthly quota exceeded');
console.error(`Used: ${error.used}/${error.limit}`);
console.error(`Resets: ${error.resetDate}`);
// Prompt user to upgrade
} else if (error instanceof NotFoundError) {
// Resource not found
console.error('Resource not found:', error.message);
} else if (error instanceof ProviderError) {
// LLM provider error
console.error(`Provider error (${error.provider}):`, error.message);
// Usually temporary - retry with backoff
} else if (error instanceof CheckError) {
// Generic API error
console.error('API error:', error.message);
console.error('Request ID:', error.requestId);
} else {
// Network or unexpected error
console.error('Unexpected error:', error);
}
}Python SDK
from check import (
Check,
CheckError,
AuthenticationError,
ValidationError,
RateLimitError,
QuotaExceededError,
NotFoundError,
ProviderError,
)
import time
client = Check(api_key="vfy_...")
try:
result = client.verify_and_wait(
content="Your content",
methods={"reasoning": 1.0}
)
except AuthenticationError as e:
# Invalid or missing API key
print(f"Authentication failed: {e.message}")
except ValidationError as e:
# Invalid request parameters
print(f"Validation failed: {e.message}")
for detail in e.details:
print(f" {detail['field']}: {detail['message']}")
except RateLimitError as e:
# Rate limited - wait and retry
print(f"Rate limited. Retry after {e.retry_after}s")
time.sleep(e.retry_after)
# Retry the request
except QuotaExceededError as e:
# Monthly quota exceeded
print(f"Monthly quota exceeded: {e.used}/{e.limit}")
print(f"Resets: {e.reset_date}")
except NotFoundError as e:
# Resource not found
print(f"Resource not found: {e.message}")
except ProviderError as e:
# LLM provider error
print(f"Provider error ({e.provider}): {e.message}")
except CheckError as e:
# Generic API error
print(f"API error: {e.message}")
print(f"Request ID: {e.request_id}")
except Exception as e:
# Network or unexpected error
print(f"Unexpected error: {e}")REST API (fetch)
async function verifyContent(content: string): Promise<any> {
const response = await fetch('https://api.check.ai/v1/verify', {
method: 'POST',
headers: {
'Authorization': `Bearer ${apiKey}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ content, methods: { reasoning: 1.0 } }),
});
if (!response.ok) {
const error = await response.json();
const requestId = error.error?.requestId;
switch (response.status) {
case 401:
throw new Error(`Authentication failed: ${error.error.message}`);
case 400:
case 422:
const details = error.error.details
?.map((d: any) => `${d.field}: ${d.message}`)
.join(', ');
throw new Error(`Validation error: ${details || error.error.message}`);
case 429:
const retryAfter = error.error.retryAfter || 60;
console.log(`Rate limited. Waiting ${retryAfter}s...`);
await new Promise(r => setTimeout(r, retryAfter * 1000));
return verifyContent(content); // Retry
case 403:
if (error.error.code === 'usage_limit_exceeded') {
throw new Error(`Monthly limit reached: ${error.error.used}/${error.error.limit}`);
}
throw new Error(`Forbidden: ${error.error.message}`);
case 404:
throw new Error(`Not found: ${error.error.message}`);
case 502:
case 503:
case 504:
// Server errors - retry with backoff
console.log(`Server error (${response.status}). Retrying...`);
await new Promise(r => setTimeout(r, 5000));
return verifyContent(content);
default:
throw new Error(`API error (${response.status}): ${error.error.message} [${requestId}]`);
}
}
return response.json();
}Best Practices
Retry Strategy
For transient errors (429, 5xx), implement exponential backoff with jitter to avoid thundering herd problems.
Implement Retries for Transient Errors
Retry these status codes with exponential backoff:
429- Rate limited (useretryAftervalue)500- Internal server error502- Bad gateway (provider issues)503- Service unavailable504- Gateway timeout
async function withRetry<T>(
fn: () => Promise<T>,
maxRetries = 3,
baseDelay = 1000
): Promise<T> {
for (let attempt = 0; attempt <= maxRetries; attempt++) {
try {
return await fn();
} catch (error: any) {
const isRetryable = [429, 500, 502, 503, 504].includes(error.status);
const isLastAttempt = attempt === maxRetries;
if (!isRetryable || isLastAttempt) {
throw error;
}
// Use retryAfter for 429, otherwise exponential backoff
const delay = error.retryAfter
? error.retryAfter * 1000
: baseDelay * Math.pow(2, attempt) + Math.random() * 1000;
console.log(`Attempt ${attempt + 1} failed. Retrying in ${delay}ms...`);
await new Promise(r => setTimeout(r, delay));
}
}
throw new Error('Unreachable');
}Don't Retry These Errors
400- Fix the request parameters401- Check your API key403- Check your permissions or plan404- Resource doesn't exist422- Fix validation errors
Log Errors with Request IDs
Always log the requestId for debugging:
if (!response.ok) {
const error = await response.json();
console.error('API Error', {
status: response.status,
code: error.error.code,
message: error.error.message,
requestId: error.error.requestId,
timestamp: new Date().toISOString(),
});
}Use Request IDs for Support
When contacting support, include:
- The
requestIdfrom the error response - The timestamp of the error
- The request you were making (without sensitive data)
This helps us trace the exact request in our logs.
Error Code Reference
| Code | HTTP Status | Description | Retry? |
|---|---|---|---|
unauthorized | 401 | Invalid API key | No |
forbidden | 403 | Insufficient permissions | No |
not_found | 404 | Resource not found | No |
validation_error | 400/422 | Invalid parameters | No |
rate_limited | 429 | Too many requests | Yes |
usage_limit_exceeded | 403 | Monthly quota exceeded | No |
provider_error | 502 | LLM provider error | Yes |
provider_timeout | 504 | Provider timeout | Yes |
internal_error | 500 | Server error | Yes |
service_unavailable | 503 | Maintenance | Yes |