Skip to main content
CID222Documentation

Error Handling

Learn how to properly handle errors from the CID222 API to build resilient applications.

Error Response Format

All API errors follow a consistent format:

Error Response
{
"statusCode": 400,
"message": "Detailed error message",
"error": "Bad Request",
"details": {
// Additional context when available
}
}

HTTP Status Codes

CodeDescriptionAction
400Bad RequestFix request body/parameters
401UnauthorizedCheck API key
403ForbiddenContent blocked or insufficient permissions
404Not FoundCheck endpoint URL or resource ID
429Rate LimitedRetry after delay
500Internal ErrorRetry with backoff
503Service UnavailableProvider down, retry later

Common Errors

Authentication Errors

401 - Invalid Token
{
"statusCode": 401,
"message": "Invalid or expired token",
"error": "Unauthorized"
}

Solutions:

  • Verify API key is correct
  • Check if key has been rotated
  • Ensure Bearer prefix is included

Content Blocked

403 - Content Blocked
{
"statusCode": 403,
"message": "Request blocked due to policy violation",
"error": "Forbidden",
"details": {
"reason": "TOXIC_CONTENT",
"category": "HATE_SPEECH",
"confidence": 0.94
}
}
When content is blocked, the request was not forwarded to the LLM. No tokens were consumed.

Rate Limiting

429 - Rate Limit
{
"statusCode": 429,
"message": "Rate limit exceeded",
"error": "Too Many Requests",
"details": {
"retry_after": 30,
"limit": 60,
"remaining": 0,
"reset": 1699900030
}
}

Handle rate limits by waiting before retrying:

Rate Limit Handler
async function handleRateLimit(response) {
const retryAfter = response.headers.get('Retry-After');
const waitTime = retryAfter ? parseInt(retryAfter) * 1000 : 30000;
console.log(`Rate limited. Waiting ${waitTime}ms...`);
await new Promise(resolve => setTimeout(resolve, waitTime));
// Retry the request
}

Stream Error Handling

SSE streams may encounter errors mid-stream:

Stream Error Handling
async function handleStream(response) {
const reader = response.body.getReader();
const decoder = new TextDecoder();
try {
while (true) {
const { done, value } = await reader.read();
if (done) break;
const chunk = decoder.decode(value);
// Check for error event
if (chunk.includes('event: error')) {
const errorData = parseStreamError(chunk);
throw new Error(errorData.message);
}
// Process normal data
processChunk(chunk);
}
} catch (error) {
console.error('Stream error:', error);
// Handle gracefully - maybe show partial response
} finally {
reader.releaseLock();
}
}
function parseStreamError(chunk) {
const match = chunk.match(/data: ({.*})/);
if (match) {
return JSON.parse(match[1]);
}
return { message: 'Unknown stream error' };
}

Retry Strategies

Different errors require different retry approaches:

Error TypeShould RetryStrategy
400 Bad RequestNoFix input and resubmit
401 UnauthorizedOnceRefresh token, then retry
403 ForbiddenNoContent violation, don't retry
429 Rate LimitedYesWait for Retry-After header
500 Server ErrorYesExponential backoff
503 UnavailableYesExponential backoff
Complete Error Handler
class CID222Client {
async request(endpoint, body, retries = 3) {
for (let attempt = 0; attempt < retries; attempt++) {
try {
const response = await fetch(`https://api.cid222.ai${endpoint}`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${this.apiKey}`,
'Content-Type': 'application/json',
},
body: JSON.stringify(body)
});
if (response.ok) {
return response.json();
}
const error = await response.json();
// Don't retry client errors
if (response.status >= 400 && response.status < 500) {
if (response.status === 429) {
const retryAfter = response.headers.get('Retry-After') || '30';
await this.sleep(parseInt(retryAfter) * 1000);
continue;
}
throw new APIError(error.message, response.status);
}
// Retry server errors with backoff
if (attempt < retries - 1) {
await this.sleep(Math.pow(2, attempt) * 1000);
continue;
}
throw new APIError(error.message, response.status);
} catch (error) {
if (attempt === retries - 1) throw error;
}
}
}
sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
}
class APIError extends Error {
constructor(message, status) {
super(message);
this.status = status;
}
}