Skip to main content

ChurnKitError

All SDK methods throw ChurnKitError on failure. It extends Error and adds status (HTTP status code) and code (typed error constant).
import { ChurnKitError, ErrorCode } from '@vgpprasad91/churnkit-sdk'

try {
  await churn.score('user_123')
} catch (err) {
  if (err instanceof ChurnKitError) {
    console.log(err.message)  // human-readable description
    console.log(err.status)   // HTTP status code (or undefined for network errors)
    console.log(err.code)     // 'TIMEOUT' | 'UNAUTHORIZED' | etc.
  }
}

Error codes

CodeHTTPWhen
ABORTEDThe caller’s AbortSignal fired
TIMEOUTRequest exceeded configured timeout
NETWORK_ERRORDNS failure, connection refused, etc.
VALIDATION_ERROR400Invalid input (empty userId, bad threshold, etc.)
UNAUTHORIZED401API key is missing, invalid, or revoked
FORBIDDEN403API key lacks permission for this operation
NOT_FOUND404Resource doesn’t exist (user not tracked, no watch, etc.)
RATE_LIMITED429Too many requests — back off and retry
SERVER_ERROR5xxChurnKit server error
PAYLOAD_TOO_LARGE413bulkEvent() exceeded 500 items

Handling patterns

Ignore cancellations

try {
  const risk = await churn.score(userId, { signal })
  return risk
} catch (err) {
  if (err instanceof ChurnKitError && err.code === ErrorCode.ABORTED) {
    return null // user navigated away — ignore
  }
  throw err
}

Exhaustive switch with type narrowing

import { ChurnKitError, ErrorCode, isKnownErrorCode } from '@vgpprasad91/churnkit-sdk'

try {
  await churn.identify(userId, traits)
} catch (err) {
  if (err instanceof ChurnKitError && isKnownErrorCode(err.code)) {
    switch (err.code) {
      case ErrorCode.UNAUTHORIZED:
        logger.error('ChurnKit API key invalid — check CHURNKIT_API_KEY')
        break
      case ErrorCode.RATE_LIMITED:
        logger.warn('ChurnKit rate limited — consider batching')
        break
      case ErrorCode.TIMEOUT:
        logger.warn('ChurnKit timeout — request took too long')
        break
      case ErrorCode.VALIDATION_ERROR:
        logger.error('ChurnKit validation error', err.message)
        break
      default:
        logger.error('ChurnKit error', err.code, err.message)
    }
  }
}

Non-blocking with error logging

async function trackSafe(userId: string, event: string) {
  try {
    await churn.event(userId, event)
  } catch (err) {
    // Never let tracking failures break the main flow
    if (err instanceof ChurnKitError) {
      logger.warn('ChurnKit track failed', { code: err.code, event })
    }
  }
}

isKnownErrorCode()

Type guard that narrows err.code to a well-known ErrorCode constant — useful for exhaustive switch statements.
import { isKnownErrorCode } from '@vgpprasad91/churnkit-sdk'

if (err instanceof ChurnKitError && isKnownErrorCode(err.code)) {
  // err.code is now typed as ErrorCode — IDE autocomplete works
  switch (err.code) { ... }
}