Skip to content

Error Handling

Handle ExtensionLogin errors gracefully in your extension.

Error Response Format

All SDK methods return errors in a consistent format:

typescript
{
  success: false,
  error: {
    code: string;      // Machine-readable error code
    message: string;   // Human-readable message
    retryAfter?: number; // Milliseconds until retry (rate limits)
  }
}

Error Codes

Authentication Errors

CodeDescriptionResolution
INVALID_API_KEYAPI key is invalid or missingCheck your API key
API_KEY_INACTIVEAPI key has been deactivatedReactivate in dashboard
EXTENSION_MISMATCHRequest from unregistered extensionRegister extension ID

Validation Errors

CodeDescriptionResolution
INVALID_EMAILEmail address is invalidValidate email format
MISSING_EMAILEmail is required but not providedInclude email field
INVALID_METADATAMetadata contains invalid typesCheck metadata format
METADATA_TOO_LARGEMetadata exceeds 10KB limitReduce metadata size

OAuth Errors

CodeDescriptionResolution
OAUTH_NOT_CONFIGUREDGoogle OAuth not set upConfigure in dashboard
USER_CANCELLEDUser closed OAuth popupNo action needed
OAUTH_FAILEDOAuth flow failedCheck credentials
INVALID_TOKENOAuth token is invalidRequest new token

Network Errors

CodeDescriptionResolution
NETWORK_ERRORNetwork request failedCheck connection
TIMEOUTRequest timed outRetry later
SERVER_ERRORAPI server errorRetry later

Rate Limiting

CodeDescriptionResolution
RATE_LIMITEDToo many requestsWait and retry

Handling Errors

Basic Error Handling

javascript
const result = await ExtensionLogin.identify({
  email: 'user@example.com'
});

if (!result.success) {
  console.error('Error:', result.error.code, result.error.message);
}

Switch on Error Code

javascript
const result = await ExtensionLogin.identify({ email });

if (!result.success) {
  switch (result.error.code) {
    case 'INVALID_EMAIL':
      showFieldError('email', 'Please enter a valid email');
      break;
    case 'RATE_LIMITED':
      showNotification('Too many attempts. Please wait.');
      break;
    case 'NETWORK_ERROR':
      showNotification('Connection error. Check your internet.');
      break;
    default:
      showNotification('Something went wrong. Please try again.');
  }
}

Try-Catch for Network Errors

javascript
async function safeIdentify(email, name) {
  try {
    const result = await ExtensionLogin.identify({ email, name });

    if (result.success) {
      return { success: true, user: result.user };
    } else {
      return { success: false, error: result.error };
    }
  } catch (error) {
    // Unexpected error (shouldn't happen normally)
    console.error('Unexpected error:', error);
    return {
      success: false,
      error: {
        code: 'UNEXPECTED_ERROR',
        message: 'An unexpected error occurred'
      }
    };
  }
}

Rate Limiting

Handling Rate Limits

javascript
const result = await ExtensionLogin.identify({ email });

if (!result.success && result.error.code === 'RATE_LIMITED') {
  const retryAfter = result.error.retryAfter || 60000;

  console.log(`Rate limited. Retry after ${retryAfter}ms`);

  // Show user-friendly message
  showNotification(`Please wait ${Math.ceil(retryAfter / 1000)} seconds`);

  // Schedule retry
  setTimeout(() => {
    retryIdentify(email);
  }, retryAfter);
}

Exponential Backoff

javascript
async function identifyWithRetry(email, maxRetries = 3) {
  let lastError;

  for (let attempt = 0; attempt < maxRetries; attempt++) {
    const result = await ExtensionLogin.identify({ email });

    if (result.success) {
      return result;
    }

    lastError = result.error;

    // Don't retry validation errors
    if (['INVALID_EMAIL', 'MISSING_EMAIL'].includes(result.error.code)) {
      return result;
    }

    // Calculate backoff
    const backoff = Math.min(1000 * Math.pow(2, attempt), 30000);
    const delay = result.error.retryAfter || backoff;

    console.log(`Attempt ${attempt + 1} failed. Retrying in ${delay}ms`);
    await new Promise(resolve => setTimeout(resolve, delay));
  }

  return { success: false, error: lastError };
}

Error Event Listener

Listen for errors globally:

javascript
ExtensionLogin.on('error', ({ code, message, context }) => {
  // Log all errors
  console.error(`[ExtensionLogin Error] ${code}: ${message}`);

  // Send to error tracking
  errorTracking.capture({
    error: `ExtensionLogin: ${code}`,
    message,
    extra: context
  });
});

User-Friendly Error Messages

Map error codes to user-friendly messages:

javascript
const errorMessages = {
  INVALID_EMAIL: 'Please enter a valid email address.',
  MISSING_EMAIL: 'Email address is required.',
  RATE_LIMITED: 'Too many attempts. Please wait a moment.',
  NETWORK_ERROR: 'Connection error. Please check your internet.',
  SERVER_ERROR: 'Our servers are having issues. Please try again.',
  OAUTH_NOT_CONFIGURED: 'Google sign-in is not available.',
  USER_CANCELLED: 'Sign-in was cancelled.',
  DEFAULT: 'Something went wrong. Please try again.'
};

function getErrorMessage(code) {
  return errorMessages[code] || errorMessages.DEFAULT;
}

// Usage
if (!result.success) {
  showNotification(getErrorMessage(result.error.code));
}

Validation Before API Call

Prevent errors by validating client-side:

javascript
function validateEmail(email) {
  const regex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
  return regex.test(email);
}

async function identifyUser(email, name) {
  // Client-side validation
  if (!email) {
    return {
      success: false,
      error: { code: 'MISSING_EMAIL', message: 'Email is required' }
    };
  }

  if (!validateEmail(email)) {
    return {
      success: false,
      error: { code: 'INVALID_EMAIL', message: 'Invalid email format' }
    };
  }

  // Proceed with API call
  return ExtensionLogin.identify({ email, name });
}

Error UI Patterns

Inline Field Errors

javascript
async function handleSubmit() {
  const email = document.getElementById('email').value;
  const emailError = document.getElementById('email-error');

  emailError.textContent = '';

  const result = await ExtensionLogin.identify({ email });

  if (!result.success) {
    if (result.error.code === 'INVALID_EMAIL') {
      emailError.textContent = 'Please enter a valid email';
      document.getElementById('email').focus();
    } else {
      showToast(getErrorMessage(result.error.code));
    }
  }
}

Toast Notifications

javascript
function showToast(message, type = 'error') {
  const toast = document.createElement('div');
  toast.className = `toast toast-${type}`;
  toast.textContent = message;

  document.body.appendChild(toast);

  setTimeout(() => toast.remove(), 5000);
}

// Usage
if (!result.success) {
  showToast(getErrorMessage(result.error.code), 'error');
}

Loading States

javascript
async function handleLogin() {
  const button = document.getElementById('login-btn');

  try {
    button.disabled = true;
    button.textContent = 'Signing in...';

    const result = await ExtensionLogin.identify({ email, name });

    if (!result.success) {
      showError(result.error);
    }
  } finally {
    button.disabled = false;
    button.textContent = 'Sign In';
  }
}

Debugging Errors

Enable Debug Mode

javascript
ExtensionLogin.init({
  apiKey: 'el_test_xxx',
  debug: true
});

// Console shows detailed error info:
// [ExtensionLogin] Error: INVALID_EMAIL
// [ExtensionLogin] Details: { email: 'invalid', ... }

Log Error Context

javascript
ExtensionLogin.on('error', ({ code, message, context }) => {
  console.group('ExtensionLogin Error');
  console.error('Code:', code);
  console.error('Message:', message);
  console.error('Context:', context);
  console.groupEnd();
});

TypeScript Error Types

typescript
import type { ExtensionLoginError } from 'extensionlogin';

interface IdentifyResult {
  success: boolean;
  user?: User;
  error?: ExtensionLoginError;
}

interface ExtensionLoginError {
  code: ErrorCode;
  message: string;
  retryAfter?: number;
}

type ErrorCode =
  | 'INVALID_API_KEY'
  | 'API_KEY_INACTIVE'
  | 'INVALID_EMAIL'
  | 'MISSING_EMAIL'
  | 'RATE_LIMITED'
  | 'NETWORK_ERROR'
  | 'SERVER_ERROR'
  | 'OAUTH_NOT_CONFIGURED'
  | 'USER_CANCELLED'
  | 'OAUTH_FAILED'
  | 'INVALID_TOKEN';

Next Steps

Built for Chrome Extension Developers