Node SDK: Error Handling
Error Types
The SDK throws typed errors for different failure scenarios:
import { Keito, KeitoError, ValidationError, AuthenticationError, RateLimitError } from '@keito/sdk';
try {
await keito.timeEntries.create({ /* ... */ });
} catch (err) {
if (err instanceof ValidationError) {
console.error(`Validation failed: ${err.message} (field: ${err.field})`);
} else if (err instanceof AuthenticationError) {
console.error('Invalid API key');
} else if (err instanceof RateLimitError) {
console.error(`Rate limited. Retry after ${err.retryAfter}s`);
} else if (err instanceof KeitoError) {
console.error(`API error: ${err.code} — ${err.message}`);
}
}
Error Properties
All KeitoError instances include:
| Property | Type | Description |
|---|---|---|
code | string | Error code (e.g., validation_error) |
message | string | Human-readable description |
status | number | HTTP status code |
field | string | Field that caused the error (validation only) |
Automatic Retries
The SDK automatically retries on 429 (rate limit) and 5xx (server error) responses:
const keito = new Keito({
maxRetries: 3, // default: 2
retryDelay: 1000, // default: 1000ms (exponential backoff)
});
Retries use exponential backoff. For 429 responses, the SDK respects the Retry-After header.
Disabling Retries
const keito = new Keito({
maxRetries: 0,
});
Handling Specific Scenarios
Agent Session Cleanup
If an agent fails mid-session, clean up the running timer:
const entry = await keito.timeEntries.create({
project_id: 'prj_abc',
hours: 0,
is_running: true,
source: 'agent',
/* ... */
});
try {
await myAgent.run();
} catch (err) {
// Discard the running timer
await keito.timeEntries.delete(entry.id);
throw err;
}
Project Not Assigned
try {
await keito.timeEntries.create({
project_id: 'prj_not_assigned',
/* ... */
});
} catch (err) {
if (err instanceof KeitoError && err.code === 'project_not_assigned') {
console.error('Agent user is not assigned to this project');
}
}