Dashboard

Error Handling

Comprehensive guide to API errors and troubleshooting

Error Codes
6 min read

Standard Error Format

All API errors follow a consistent response structure

Error Response Structure

{
  "success": false,
  "error": "Human-readable error message",
  "code": "MACHINE_READABLE_ERROR_CODE",
  "details": {
    "field": "Additional context about the error",
    "value": "Invalid value that caused the error",
    "expected": "What was expected instead"
  },
  "timestamp": "2024-01-16T10:30:00.000Z",
  "requestId": "req_1234567890abcdef"
}

Response Fields

success

Always false for error responses

error

Human-readable error description

code

Machine-readable error identifier

Optional Fields

details

Additional context and debugging info

timestamp

When the error occurred

requestId

Unique identifier for support

Client Errors (4xx)

Errors caused by invalid requests

400

Bad Request

The request is malformed or contains invalid data.

{
  "success": false,
  "error": "Validation failed",
  "code": "VALIDATION_ERROR",
  "details": {
    "field": "email",
    "value": "invalid-email",
    "message": "Must be a valid email address"
  }
}
Common causes:
  • Missing required fields
  • Invalid email format
  • Invalid phone number format
  • Invalid status value
404

Not Found

The requested resource doesn't exist.

{
  "success": false,
  "error": "Lead not found",
  "code": "LEAD_NOT_FOUND",
  "details": {
    "leadId": "lead_nonexistent123",
    "message": "No lead found with this ID in your workspace"
  }
}
Common causes:
  • Lead ID doesn't exist
  • Lead was deleted
  • Lead belongs to different workspace
  • Typo in the lead ID
409

Conflict

The request conflicts with existing data.

{
  "success": false,
  "error": "Email already exists",
  "code": "DUPLICATE_EMAIL",
  "details": {
    "email": "john.doe@example.com",
    "existingLeadId": "lead_existing123",
    "message": "A lead with this email already exists in your workspace"
  }
}
Common causes:
  • Duplicate email address
  • Lead already exists
  • Concurrent modification

Robust Error Handling

Production-ready error handling patterns

JavaScript Error Handler

class LeadAPIClient {
  constructor(apiKey, baseURL = 'https://your-domain.com/api/v1') {
    this.apiKey = apiKey;
    this.baseURL = baseURL;
  }

  async makeRequest(endpoint, options = {}) {
    const url = `${this.baseURL}${endpoint}`;
    const config = {
      headers: {
        'Authorization': `Bearer ${this.apiKey}`,
        'Content-Type': 'application/json',
        ...options.headers
      },
      ...options
    };

    try {
      const response = await fetch(url, config);
      
      // Handle rate limiting
      if (response.status === 429) {
        const retryAfter = response.headers.get('Retry-After');
        throw new RateLimitError(
          'Rate limit exceeded',
          parseInt(retryAfter),
          response.headers
        );
      }
      
      // Parse response
      const data = await response.json();
      
      // Handle API errors
      if (!response.ok) {
        throw new APIError(
          data.error || 'Unknown error',
          response.status,
          data.code,
          data.details
        );
      }
      
      return data;
    } catch (error) {
      // Handle network errors
      if (error.name === 'TypeError' || error.name === 'NetworkError') {
        throw new NetworkError('Network connection failed', error);
      }
      
      throw error;
    }
  }

  async createLead(leadData) {
    return this.makeRequest('/leads', {
      method: 'POST',
      body: JSON.stringify(leadData)
    });
  }
}

// Custom error classes
class APIError extends Error {
  constructor(message, status, code, details) {
    super(message);
    this.name = 'APIError';
    this.status = status;
    this.code = code;
    this.details = details;
  }
}

class RateLimitError extends APIError {
  constructor(message, retryAfter, headers) {
    super(message, 429, 'RATE_LIMIT_EXCEEDED');
    this.retryAfter = retryAfter;
    this.headers = headers;
  }
}

class NetworkError extends Error {
  constructor(message, originalError) {
    super(message);
    this.name = 'NetworkError';
    this.originalError = originalError;
  }
}

// Usage with error handling
async function createLeadSafely(apiClient, leadData) {
  try {
    const result = await apiClient.createLead(leadData);
    return result;
  } catch (error) {
    if (error instanceof RateLimitError) {
      // Implement retry logic
    } else if (error instanceof APIError) {
      console.error(`API Error (${error.status}): ${error.message}`);
      if (error.details) {
        console.error('Details:', error.details);
      }
    } else if (error instanceof NetworkError) {
      console.error('Network error. Please check your connection.');
    } else {
      console.error('Unexpected error:', error);
    }
    
    throw error;
  }
}

Python Error Handler

import requests
import time
from typing import Dict, Any, Optional

class LeadAPIError(Exception):
    def __init__(self, message: str, status: int, code: str = None, details: Dict = None):
        super().__init__(message)
        self.status = status
        self.code = code
        self.details = details or {}

class RateLimitError(LeadAPIError):
    def __init__(self, message: str, retry_after: int, headers: Dict):
        super().__init__(message, 429, 'RATE_LIMIT_EXCEEDED')
        self.retry_after = retry_after
        self.headers = headers

class LeadAPIClient:
    def __init__(self, api_key: str, base_url: str = 'https://your-domain.com/api/v1'):
        self.api_key = api_key
        self.base_url = base_url
        self.session = requests.Session()
        self.session.headers.update({
            'Authorization': f'Bearer {api_key}',
            'Content-Type': 'application/json'
        })

    def make_request(self, endpoint: str, method: str = 'GET', data: Dict = None) -> Dict[str, Any]:
        url = f'{self.base_url}{endpoint}'
        
        try:
            response = self.session.request(method, url, json=data)
            
            # Handle rate limiting
            if response.status_code == 429:
                retry_after = int(response.headers.get('Retry-After', 60))
                raise RateLimitError(
                    'Rate limit exceeded',
                    retry_after,
                    dict(response.headers)
                )
            
            # Parse JSON response
            try:
                json_data = response.json()
            except ValueError:
                raise LeadAPIError(f'Invalid JSON response', response.status_code)
            
            # Handle API errors
            if not response.ok:
                raise LeadAPIError(
                    json_data.get('error', 'Unknown error'),
                    response.status_code,
                    json_data.get('code'),
                    json_data.get('details')
                )
            
            return json_data
            
        except requests.exceptions.RequestException as e:
            raise LeadAPIError(f'Network error: {str(e)}', 0)
    
    def create_lead(self, lead_data: Dict[str, Any]) -> Dict[str, Any]:
        return self.make_request('/leads', 'POST', lead_data)
    
    def create_lead_with_retry(self, lead_data: Dict[str, Any], max_retries: int = 3) -> Dict[str, Any]:
        for attempt in range(max_retries + 1):
            try:
                return self.create_lead(lead_data)
            except RateLimitError as e:
                if attempt < max_retries:
                    print(f'Rate limited. Waiting {e.retry_after} seconds... (attempt {attempt + 1})')
                    time.sleep(e.retry_after)
                else:
                    raise
            except LeadAPIError as e:
                if e.status >= 500 and attempt < max_retries:
                    # Retry server errors with exponential backoff
                    wait_time = 2 ** attempt
                    print(f'Server error. Retrying in {wait_time} seconds... (attempt {attempt + 1})')
                    time.sleep(wait_time)
                else:
                    raise

# Usage example
def create_lead_safely(api_client: LeadAPIClient, lead_data: Dict[str, Any]):
    try:
        result = api_client.create_lead_with_retry(lead_data)
        print(f"Lead created: {result['data']['id']}")
        return result
    except LeadAPIError as e:
        print(f"API Error ({e.status}): {e}")
        if e.details:
            print(f"Details: {e.details}")
        raise
    except Exception as e:
        print(f"Unexpected error: {e}")
        raise

Quick Troubleshooting

Common issues and their solutions

✓ Quick Fixes

401 Unauthorized:

Check API key format and Authorization header

400 Bad Request:

Validate required fields (name, email)

404 Not Found:

Verify the lead ID exists in your workspace

429 Rate Limited:

Wait for the Retry-After time and implement backoff

🔧 Debug Tips

Check Headers:

Verify rate limit headers in responses

Save Request ID:

Include requestId when contacting support

Test with cURL:

Isolate issues by testing with command line

Monitor Usage:

Track API usage in your workspace dashboard

Error Handling Mastered!

You now know how to handle all API errors gracefully. Ready to see complete code examples in action?

    PollyBot.ai - Smart Conversations, Seamless Automation