Error Handling
GuideHandle API errors gracefully with typed exceptions, rate limit retries, and idempotency keys. Examples shown for both Node.js and Python.
Error Codes Reference
| Code | HTTP | Description | Node.js | Python |
|---|---|---|---|---|
| invalid_email | 400 | Email format is invalid | BearLumenApiError | InvalidEmailError |
| duplicate_customer | 400 | End user with this external ID already exists | BearLumenApiError | DuplicateCustomerError |
| invalid_request | 400 | Request parameters are invalid | BearLumenApiError | InvalidRequestError |
| authentication_error | 401 | API key is invalid or missing | BearLumenApiError | AuthenticationError |
| not_found | 404 | Requested resource does not exist | BearLumenApiError | NotFoundError |
| rate_limit_exceeded | 429 | Too many requests, retry after delay | BearLumenApiError | RateLimitError |
| server_error | 500 | Internal server error | BearLumenApiError | BearLumenError |
| network_error | — | Network connectivity issue | BearLumenApiError | NetworkError |
Basic Error Handling
Use instanceof checks with BearLumenApiError and switch on the error.code property:
import { BearLumen, BearLumenApiError } from '@bearlumen/node-sdk';
try {
const { endUser } = await bearLumen.endUsers.create({
externalId: 'user_123',
name: 'AI Startup Inc',
});
} catch (error) {
if (error instanceof BearLumenApiError) {
switch (error.code) {
case 'invalid_email':
console.error('Invalid email format');
break;
case 'duplicate_customer':
console.error('End user already exists');
break;
case 'rate_limit_exceeded':
console.error(`Rate limit hit, retry after ${error.retryAfter} seconds`);
break;
case 'authentication_error':
console.error('Invalid API key');
break;
default:
console.error(`Error: ${error.message}`);
}
}
}Rate Limit Handling
When you hit a rate limit, the error.retryAfter property tells you how long to wait. Here is a simple retry pattern with exponential backoff:
import { BearLumenApiError } from '@bearlumen/node-sdk';
async function withRetry<T>(
fn: () => Promise<T>,
maxRetries = 3,
): Promise<T> {
for (let attempt = 0; attempt <= maxRetries; attempt++) {
try {
return await fn();
} catch (error) {
if (
error instanceof BearLumenApiError &&
error.code === 'rate_limit_exceeded' &&
attempt < maxRetries
) {
const delay = error.retryAfter
? error.retryAfter * 1000
: Math.pow(2, attempt) * 1000;
console.log(`Rate limited. Retrying in ${delay}ms...`);
await new Promise((resolve) => setTimeout(resolve, delay));
continue;
}
throw error;
}
}
throw new Error('Max retries exceeded');
}
// Usage
const result = await withRetry(() =>
bearLumen.usage.record({
eventType: 'token_usage',
metricName: 'llm_tokens',
quantity: 1500,
idempotencyKey: 'unique-key',
})
);Idempotency Keys
Idempotency keys prevent duplicate billing when the same usage event is sent more than once. Use deterministic keys based on your business entities (invoice IDs, line numbers, etc.) rather than random values:
// Use deterministic keys to prevent duplicate billing
await bearLumen.usage.record({
eventType: 'token_usage',
metricName: 'llm_tokens',
quantity: 1500,
idempotencyKey: `invoice-${invoiceId}-line-${lineNum}`,
});
// Check if the event was actually recorded
const result = await bearLumen.usage.record({
eventType: 'token_usage',
metricName: 'llm_tokens',
quantity: 1500,
idempotencyKey: 'same-key-again',
});
if (!result.recorded) {
console.log('Duplicate event skipped');
}Tip: Duplicate events return recorded: false. Always check this value after recording usage events.
Best Practices
- 1
Always use idempotency keys for usage recording. Deterministic keys based on your business entities prevent duplicate billing from retries or network issues.
- 2
Handle rate limits with exponential backoff. Respect the
retryAfter/retry_aftervalue when available, otherwise use increasing delays. - 3
Log error codes and messages for debugging. Error codes are stable identifiers you can use in alerting and log analysis.
- 4
Use specific error types over generic catch-all. In Python, catch specific exceptions like
RateLimitErrorbeforeBearLumenError. In Node.js, checkerror.codefor specific handling. - 5
Check the recorded flag after usage.record() calls. Use
result.recorded(Node.js) orresult['recorded'](Python) to confirm the event was actually recorded.