Appearance
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
| Code | Description | Resolution |
|---|---|---|
INVALID_API_KEY | API key is invalid or missing | Check your API key |
API_KEY_INACTIVE | API key has been deactivated | Reactivate in dashboard |
EXTENSION_MISMATCH | Request from unregistered extension | Register extension ID |
Validation Errors
| Code | Description | Resolution |
|---|---|---|
INVALID_EMAIL | Email address is invalid | Validate email format |
MISSING_EMAIL | Email is required but not provided | Include email field |
INVALID_METADATA | Metadata contains invalid types | Check metadata format |
METADATA_TOO_LARGE | Metadata exceeds 10KB limit | Reduce metadata size |
OAuth Errors
| Code | Description | Resolution |
|---|---|---|
OAUTH_NOT_CONFIGURED | Google OAuth not set up | Configure in dashboard |
USER_CANCELLED | User closed OAuth popup | No action needed |
OAUTH_FAILED | OAuth flow failed | Check credentials |
INVALID_TOKEN | OAuth token is invalid | Request new token |
Network Errors
| Code | Description | Resolution |
|---|---|---|
NETWORK_ERROR | Network request failed | Check connection |
TIMEOUT | Request timed out | Retry later |
SERVER_ERROR | API server error | Retry later |
Rate Limiting
| Code | Description | Resolution |
|---|---|---|
RATE_LIMITED | Too many requests | Wait 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
- SDK Methods - Full API reference
- Events - Listen for error events
- Examples - See error handling in action