Skip to content

Error Handling ​

Properly handling errors is essential for building robust messaging applications with the MsGine SDK.

Error Types ​

The SDK throws different types of errors depending on the situation:

MsGineError ​

The base error class for all API errors:

typescript
import { MsGineError } from '@msgine/sdk'

try {
  await client.sms.send({
    to: '+256701521269',
    message: 'Hello!'
  })
} catch (error) {
  if (error instanceof MsGineError) {
    console.error('MsGine API Error:', error.message)
    console.error('Status Code:', error.statusCode)
    console.error('Error Code:', error.code)
  }
}

MsGineValidationError ​

Thrown when input fails validation before reaching the API:

typescript
import { MsGineValidationError } from '@msgine/sdk'

try {
  await client.sms.send({
    to: 'invalid-number',
    message: 'Hello!'
  })
} catch (error) {
  if (error instanceof MsGineValidationError) {
    console.error('Validation failed:', error.message)
    if (error.field) {
      console.error('Invalid field:', error.field)
    }
  }
}

Error Properties ​

ClassPropertyTypeDescription
MsGineErrormessagestringHuman-readable error description
MsGineErrorstatusCodenumberHTTP status code (e.g., 400, 401, 500)
MsGineErrorcodestringMachine-readable error code
MsGineValidationErrormessagestringValidation failure description
MsGineValidationErrorfieldstring?The field that failed validation

Common Error Codes ​

Authentication Errors ​

typescript
{
  code: 'unauthorized',
  statusCode: 401,
  message: 'Invalid or missing API key'
}

Solutions:

  • Verify your API key is correct
  • Check that the key hasn't been revoked
  • Ensure the key is properly loaded from environment variables

Validation Errors ​

typescript
{
  code: 'invalid_phone_number',
  statusCode: 400,
  message: 'The phone number must be in E.164 format',
  details: {
    field: 'to',
    value: '0701234567'
  }
}

Solutions:

  • Use E.164 format: +[country code][number]
  • Example: +256701521269 (not 0701521269)

Rate Limit Errors ​

typescript
{
  code: 'rate_limit_exceeded',
  statusCode: 429,
  message: 'Too many requests. Please try again later.',
  details: {
    retryAfter: 60
  }
}

Solutions:

  • Implement request queuing for high-volume applications
  • Respect the retryAfter value before retrying

Insufficient Balance ​

typescript
{
  code: 'insufficient_balance',
  statusCode: 402,
  message: 'Insufficient account balance'
}

Solutions:

Error Handling Best Practices ​

1. Always Use Try-Catch ​

typescript
async function sendMessage() {
  try {
    const result = await client.sms.send({
      to: '+256701521269',
      message: 'Hello!'
    })
    return result
  } catch (error) {
    if (error instanceof MsGineValidationError) {
      // Handle input validation errors
      console.error('Invalid input:', error.message, error.field)
    } else if (error instanceof MsGineError) {
      // Handle API errors
      console.error('API Error:', error.code, error.message)
    } else {
      // Handle unexpected errors
      console.error('Unexpected error:', error)
    }
    throw error
  }
}

2. Check Error Codes ​

typescript
try {
  await client.sms.send({ to: phone, message: text })
} catch (error) {
  if (error instanceof MsGineError) {
    switch (error.code) {
      case 'invalid_phone_number':
        console.error('Invalid phone:', error.details)
        break
      case 'rate_limit_exceeded':
        console.error('Rate limited, retry after:', error.details?.retryAfter)
        break
      case 'unauthorized':
        console.error('Authentication failed — check your API key')
        break
      case 'insufficient_balance':
        console.error('Low balance — top up at msgine.net/billing')
        break
      default:
        console.error('API error:', error.message)
    }
  }
}

3. Graceful Degradation ​

typescript
async function sendSmsWithFallback(to: string, message: string) {
  try {
    return await client.sms.send({ to, message })
  } catch (error) {
    if (error instanceof MsGineError) {
      // Log to monitoring service
      await logToMonitoring(error)

      // Attempt fallback notification method
      await sendEmailNotification(to, message)

      return null
    }
    throw error
  }
}

4. Retry on Transient Errors ​

typescript
async function sendWithRetry(to: string, message: string, maxAttempts = 3) {
  for (let attempt = 1; attempt <= maxAttempts; attempt++) {
    try {
      return await client.sms.send({ to, message })
    } catch (error) {
      if (
        error instanceof MsGineError &&
        (error.statusCode === 429 || error.statusCode >= 500) &&
        attempt < maxAttempts
      ) {
        const delay = Math.pow(2, attempt) * 1000
        console.log(`Attempt ${attempt} failed, retrying in ${delay}ms`)
        await new Promise(resolve => setTimeout(resolve, delay))
      } else {
        throw error
      }
    }
  }
}

Validation Errors ​

The SDK validates inputs before making API requests. This catches obvious mistakes early:

typescript
try {
  await client.sms.send({
    to: 'not-a-phone-number', // Will throw MsGineValidationError
    message: 'Hello!'
  })
} catch (error) {
  if (error instanceof MsGineValidationError) {
    // Validation happened client-side — no API call was made
    console.error('Validation error:', error.message)
    if (error.field) {
      console.error('Problem field:', error.field)
    }
  }
}

Next Steps ​

Released under the MIT License.