Error Handling
Learn how to properly handle errors in your Cognipeer Console SDK applications.
Error Types
The SDK throws two error classes. CognipeerAPIError extends CognipeerError, which extends the native Error:
class CognipeerError extends Error {
statusCode?: number; // HTTP status code
response?: unknown; // the parsed response body
}
class CognipeerAPIError extends CognipeerError {
errorType?: string; // the body's error.type, e.g. 'invalid_request_error'
errorCode?: string; // the body's error.code (or a top-level `code`) — branch on this
retryAfterMs?: number; // parsed Retry-After header, in milliseconds, when present
}An HTTP error response is always a CognipeerAPIError. A request that is aborted (your own signal, or the client timeout) rejects with the runtime's AbortError, not a CognipeerError.
Basic Error Handling
Always wrap SDK calls in try-catch blocks:
import { ConsoleClient, CognipeerError } from '@cognipeer/console-sdk';
const client = new ConsoleClient({ apiKey: 'your-api-key' });
try {
const response = await client.chat.completions.create({
model: 'gpt-4',
messages: [{ role: 'user', content: 'Hello!' }],
});
console.log(response.choices[0].message.content);
} catch (error) {
if (error instanceof CognipeerError) {
console.error('Cognipeer Console SDK Error:', error.message);
console.error('Status:', error.statusCode);
console.error('Code:', error.errorCode);
} else {
console.error('Unexpected error:', error);
}
}Common Error Codes
Authentication Errors (401)
try {
const response = await client.chat.completions.create({...});
} catch (error) {
if (error instanceof CognipeerError && error.statusCode === 401) {
console.error('Invalid API key. Please check your credentials.');
// Handle authentication error
}
}Rate Limiting (429)
try {
const response = await client.chat.completions.create({...});
} catch (error) {
if (error instanceof CognipeerError && error.statusCode === 429) {
console.error('Rate limit exceeded. Please retry after some time.');
// Implement exponential backoff
}
}Invalid Request (400)
try {
const response = await client.chat.completions.create({...});
} catch (error) {
if (error instanceof CognipeerError && error.statusCode === 400) {
console.error('Invalid request:', error.message);
// Check request parameters
}
}Model Not Found (404)
try {
const response = await client.chat.completions.create({
model: 'non-existent-model',
messages: [{ role: 'user', content: 'Hello' }],
});
} catch (error) {
if (error instanceof CognipeerError && error.statusCode === 404) {
console.error('Model not found:', error.message);
// Use a different model
}
}Server Errors (500+)
try {
const response = await client.chat.completions.create({...});
} catch (error) {
if (error instanceof CognipeerError && error.statusCode && error.statusCode >= 500) {
console.error('Server error. Please try again later.');
// Implement retry logic
}
}Machine-readable error codes
error.statusCode tells you the class of failure; error.errorCode tells you which rule was hit. Branch on it, never on the message text. The helpers isAgentRunErrorCode and isAgentActionErrorCode narrow the error and give you typed constants:
import {
CognipeerAPIError,
AgentRunErrorCodes,
AgentActionErrorCodes,
isAgentRunErrorCode,
isAgentActionErrorCode,
} from '@cognipeer/console-sdk';
try {
await client.agents.responses.create({ model: 'support-bot', session_id: id, input: 'Hi' });
} catch (error) {
if (isAgentRunErrorCode(error, AgentRunErrorCodes.Conflict)) {
// 409 agent_run_conflict: a run is already active on this conversation
} else if (isAgentActionErrorCode(error, AgentActionErrorCodes.SessionNotFound)) {
// 404 session_not_found
} else if (isAgentActionErrorCode(error, AgentActionErrorCodes.PendingAction)) {
// 409 pending_action: answer the open approvals/questions first
} else if (error instanceof CognipeerAPIError && error.errorCode === 'agent_not_active') {
// codes without a constant are plain strings
} else {
throw error;
}
}Webhook routes answer { error: '<message>', code: '<code>' }; the SDK reads the top-level code into errorCode too, so not_found, forbidden, limit_reached, endpoint_disabled and delivery_pending are available. Extra fields of the body (action_status, pending_action_ids, spent_usd, decisionId, …) are on error.response.
The full list of codes, with status and meaning, is on Agent error codes.
What the SDK retries for you
The client retries 429, 502, 503 and 504 up to maxRetries times (default 3) with exponential backoff, honouring Retry-After up to 30 seconds. A longer Retry-After is thrown with retryAfterMs set so you can reschedule. A server can veto the retry with { error: { retryable: false } } — a synchronous agent 504 timeout is never retried. Other statuses (400, 401, 402, 403, 404, 409, 410, …) are thrown at once.
Retry Logic
Implement exponential backoff for transient errors:
async function withRetry<T>(
fn: () => Promise<T>,
maxRetries = 3,
delay = 1000
): Promise<T> {
for (let i = 0; i < maxRetries; i++) {
try {
return await fn();
} catch (error) {
if (error instanceof CognipeerError) {
// Retry on rate limits and server errors
if (error.statusCode === 429 || (error.statusCode && error.statusCode >= 500)) {
if (i < maxRetries - 1) {
const waitTime = delay * Math.pow(2, i);
console.log(`Retrying in ${waitTime}ms...`);
await new Promise(resolve => setTimeout(resolve, waitTime));
continue;
}
}
}
throw error;
}
}
throw new Error('Max retries reached');
}
// Usage
try {
const response = await withRetry(() =>
client.chat.completions.create({
model: 'gpt-4',
messages: [{ role: 'user', content: 'Hello!' }],
})
);
console.log(response);
} catch (error) {
console.error('Failed after retries:', error);
}Timeout Handling
Set custom timeouts for requests. When the timeout elapses, the request is aborted and rejects with an AbortError (the same error you get when you abort with your own signal):
const client = new ConsoleClient({
apiKey: 'your-api-key',
timeout: 30000, // 30 seconds
});
try {
const response = await client.chat.completions.create({...});
} catch (error) {
if (error instanceof Error && error.name === 'AbortError') {
console.error('Request timed out or was aborted');
// Handle timeout
}
}A synchronous agent turn that outlives the server's ceiling is different: the Console answers 504 with errorCode === 'timeout', and the SDK does not retry it (tool side effects may already have happened). Use background: true for long turns — see Agents → Background runs.
Validation Errors
Validate input before making API calls:
function validateMessages(messages: ChatMessage[]) {
if (!messages || messages.length === 0) {
throw new Error('Messages array cannot be empty');
}
for (const message of messages) {
if (!message.role || !message.content) {
throw new Error('Each message must have role and content');
}
}
}
try {
validateMessages(messages);
const response = await client.chat.completions.create({
model: 'gpt-4',
messages,
});
} catch (error) {
console.error('Validation error:', error);
}Streaming Errors
Handle errors in streaming responses:
try {
const stream = await client.chat.completions.create({
model: 'gpt-4',
messages: [{ role: 'user', content: 'Hello!' }],
stream: true,
});
for await (const chunk of stream) {
process.stdout.write(chunk.choices[0]?.delta?.content || '');
}
} catch (error) {
if (error instanceof CognipeerError) {
console.error('Streaming error:', error.message);
}
}Error Recovery
Implement graceful degradation:
async function getChatResponse(prompt: string) {
const models = ['gpt-4', 'gpt-3.5-turbo', 'gpt-3.5-turbo-16k'];
for (const model of models) {
try {
const response = await client.chat.completions.create({
model,
messages: [{ role: 'user', content: prompt }],
});
return response.choices[0].message.content;
} catch (error) {
if (error instanceof CognipeerError) {
if (error.statusCode === 404) {
console.log(`Model ${model} not available, trying next...`);
continue;
}
}
throw error;
}
}
throw new Error('All models failed');
}Best Practices
- Always catch errors: Never leave SDK calls unhandled
- Check error types: Use
instanceof CognipeerErrorto identify SDK errors - Log errors: Include status codes and error messages in logs
- Implement retries: Use exponential backoff for transient errors
- Validate input: Check parameters before making API calls
- Set timeouts: Configure appropriate timeouts for your use case
- Graceful degradation: Have fallback strategies for failures
- Monitor errors: Track error rates in production
Error Response Format
The API returns errors in the following format:
{
"error": {
"message": "Invalid API key",
"type": "authentication_error",
"code": "invalid_api_key"
}
}Network Errors
Handle network-related issues:
try {
const response = await client.chat.completions.create({...});
} catch (error) {
if (error instanceof TypeError && error.message.includes('fetch')) {
console.error('Network error. Check your internet connection.');
} else if (error instanceof CognipeerError) {
console.error('API error:', error.message);
}
}Related
- Configuration - Configure timeouts and retries
- Client API - Client initialization options
- Type Safety - Type-safe error handling
- Agent error codes - Every
errorCodeof the agent, session, file and webhook routes

