Errors and retries

Which errors calsdk throws, how to check for them, and what it retries for you.

Google and Outlook describe a missing event or a rejected token in different JSON, and your app shouldn't need to know either format. Every error calsdk throws extends CalsdkError, and provider API failures are mapped to the same classes on every provider, so a 404 from Google and a 404 from Outlook are both a NotFoundError.

Check errors with isInstance

import { AuthenticationError, NotFoundError, getEvent } from '@cal-sdk/core';

try {
  await getEvent({ calendar, eventId });
} catch (error) {
  if (NotFoundError.isInstance(error)) return null;
  if (AuthenticationError.isInstance(error)) return reconnect(user);
  throw error;
}

Use isInstance rather than instanceof. It still works when your app ends up with two copies of calsdk installed, where instanceof returns false for an error thrown by the other copy.

What to do with each

ErrorThrown whenUsually
InvalidArgumentErrorAn input value is invalidFix the call. argument names the field
AuthenticationErrorThe token or password was rejected (401)Refresh the token or ask the user to reconnect
PermissionDeniedErrorThe user may not do this (403)Ask for a wider scope, or skip this calendar
NotFoundErrorThe calendar or event does not exist or is hidden (404, 410)Drop your copy. resource is 'calendar' or 'event'
ConflictErrorifMatch no longer matches (412)Read the event again and retry
RateLimitErrorThe provider is throttling (429)Retried for you. If it still fails, try later; retryAfterMs says when
UnsupportedFunctionalityErrorThe provider cannot do thisCheck capabilities, or offer something else
SyncCursorExpiredErrorThe sync cursor is no longer acceptedDrop the cursor and sync from scratch
FreeBusyUnavailableErrorfindFreeTime could not read a calendarLeave that calendar out, or ask for access
APICallErrorAny other failed requeststatusCode and isRetryable say more
InvalidResponseDataErrorThe provider sent data calsdk did not expectReport it: it is a provider bug
NoSuchProviderVersionErrorA provider built for another calsdk versionUpdate calsdk and the provider together

The errors reference lists every field.

Retries

calsdk retries these for you, twice by default:

  • Rate limits (RateLimitError, or a 429).
  • Timeouts (408), server errors (5xx) and network failures, marked isRetryable on APICallError.

It waits 1 second, then 2, doubling each time, or as long as the provider's Retry-After header says. A Retry-After over a minute is not waited out: the error is thrown, so a request never hangs, and your app can schedule the work for later.

Creates only retry rate limits. A rate limit means the provider did nothing, but a server error might come after the event was saved, and retrying could create it twice. Deletes that find the event already gone on a retry count as done.

await listEvents({ calendar, timeMin, timeMax, maxRetries: 5 });
await createEvent({ calendar, event, maxRetries: 0 }); // no retries

Cancel a call

Pass an AbortSignal to stop a call, including any wait between retries:

await listEvents({ calendar, timeMin, timeMax, abortSignal: AbortSignal.timeout(10_000) });

Private data stays out of messages

Error messages tend to end up in logs and error trackers, so they leave out what may be personal. Calendar ids are often email addresses, so NotFoundError, SyncCursorExpiredError and FreeBusyUnavailableError keep them in fields, not in the message. APICallError never stores request headers, which carry the access token. Response bodies are kept in responseBody for debugging, so be careful where you log them.

On this page