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:

PropertyTypeDescription
codestringError code (e.g., validation_error)
messagestringHuman-readable description
statusnumberHTTP status code
fieldstringField 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');
  }
}