Skip to content

REST API

REST API - Error Handling

Comprehensive guide to understanding and handling API errors, including error codes, messages, and best practices.

Last updated Aug 19, 2026 · 10 min read

Comprehensive guide to understanding and handling API errors, including error codes, messages, and best practices.

📋 Table of Contents


Overview

The HelpDesk Pro API uses standard HTTP status codes and provides detailed error messages to help you understand and resolve issues quickly.

Error Response Structure

All error responses follow a consistent format:

{
  "success": false,
  "message": "Error description",
  "errors": {
    "field_name": ["Error message for this field"]
  },
  "meta": {
    "timestamp": "2025-01-15T10:30:00.000000Z",
    "version": "v1"
  }
}

Error Response Format

Standard Error Response

{
  "success": false,
  "message": "The given data was invalid.",
  "errors": {
    "email": ["The email field is required."],
    "password": ["The password must be at least 8 characters."]
  },
  "meta": {
    "timestamp": "2025-01-15T10:30:00.000000Z",
    "version": "v1"
  }
}

Simple Error Response

For errors without field-specific issues:

{
  "success": false,
  "message": "Resource not found",
  "meta": {
    "timestamp": "2025-01-15T10:30:00.000000Z",
    "version": "v1"
  }
}

HTTP Status Codes

2xx Success

Code Meaning Description
200 OK Request successful
201 Created Resource created successfully
204 No Content Request successful, no content to return

4xx Client Errors

Code Meaning Description
400 Bad Request Invalid request format or parameters
401 Unauthorized Authentication required or token invalid
403 Forbidden User lacks permission for this resource
404 Not Found Requested resource doesn't exist
422 Unprocessable Entity Validation failed
429 Too Many Requests Rate limit exceeded

5xx Server Errors

Code Meaning Description
500 Internal Server Error Unexpected server error
503 Service Unavailable Service temporarily unavailable

Common Error Scenarios

401 Unauthorized

Cause: Missing or invalid authentication token.

Response:

{
  "success": false,
  "message": "Unauthenticated",
  "meta": {
    "timestamp": "2025-01-15T10:30:00.000000Z",
    "version": "v1"
  }
}

Solution:

  • Verify token is included in Authorization header
  • Check token format: Bearer {token}
  • Re-authenticate to get a new token
  • Ensure token hasn't been revoked

Example Handling:

if (response.status === 401) {
  // Clear stored token
  localStorage.removeItem('api_token');
  // Redirect to login
  window.location.href = '/login';
}

403 Forbidden

Cause: User doesn't have permission to access the resource.

Response:

{
  "success": false,
  "message": "This action is unauthorized.",
  "meta": {
    "timestamp": "2025-01-15T10:30:00.000000Z",
    "version": "v1"
  }
}

Solution:

  • Verify user role has required permissions
  • Check resource ownership (for user-specific resources)
  • Contact administrator for permission changes

Example Handling:

if (response.status === 403) {
  showError('You do not have permission to perform this action.');
}

404 Not Found

Cause: Requested resource doesn't exist.

Response:

{
  "success": false,
  "message": "Ticket not found",
  "meta": {
    "timestamp": "2025-01-15T10:30:00.000000Z",
    "version": "v1"
  }
}

Solution:

  • Verify resource ID is correct
  • Check if resource was deleted
  • Ensure you're using the correct endpoint

Example Handling:

if (response.status === 404) {
  showError('The requested resource was not found.');
}

422 Validation Error

Cause: Request data failed validation.

Response:

{
  "success": false,
  "message": "The given data was invalid.",
  "errors": {
    "email": [
      "The email field is required.",
      "The email must be a valid email address."
    ],
    "password": [
      "The password must be at least 8 characters.",
      "The password confirmation does not match."
    ]
  },
  "meta": {
    "timestamp": "2025-01-15T10:30:00.000000Z",
    "version": "v1"
  }
}

Solution:

  • Review error messages for each field
  • Ensure all required fields are provided
  • Verify data types match expected format
  • Check field-specific validation rules

Example Handling:

if (response.status === 422) {
  const errors = response.data.errors;
  // Display field-specific errors
  Object.keys(errors).forEach(field => {
    showFieldError(field, errors[field][0]);
  });
}

429 Too Many Requests

Cause: Rate limit exceeded.

Response Headers:

X-RateLimit-Limit: 60
X-RateLimit-Remaining: 0
Retry-After: 15

Response:

{
  "success": false,
  "message": "Too Many Requests",
  "meta": {
    "timestamp": "2025-01-15T10:30:00.000000Z",
    "version": "v1"
  }
}

Solution:

  • Wait for rate limit window to reset
  • Check Retry-After header for wait time
  • Implement request throttling
  • Reduce request frequency

Example Handling:

if (response.status === 429) {
  const retryAfter = response.headers.get('Retry-After');
  const waitTime = parseInt(retryAfter) * 1000;
  
  setTimeout(() => {
    // Retry request
    retryRequest();
  }, waitTime);
}

500 Internal Server Error

Cause: Unexpected server error.

Response:

{
  "success": false,
  "message": "Internal server error",
  "meta": {
    "timestamp": "2025-01-15T10:30:00.000000Z",
    "version": "v1"
  }
}

Solution:

  • Retry request after a short delay
  • Check API status page
  • Contact support if issue persists
  • Report the error with request details

Validation Errors

Validation errors provide detailed information about what went wrong with your request data.

Field-Level Errors

Each field can have multiple error messages:

{
  "errors": {
    "email": [
      "The email field is required.",
      "The email must be a valid email address."
    ],
    "password": [
      "The password must be at least 8 characters."
    ]
  }
}

Common Validation Rules

Field Rules Example Error
email required, email format "The email must be a valid email address."
password required, min:8 "The password must be at least 8 characters."
subject required, max:255 "The subject may not be greater than 255 characters."
priority_id exists in priorities table "The selected priority id is invalid."
status_id exists in status table "The selected status id is invalid."

Handling Validation Errors

JavaScript Example:

function handleValidationErrors(errors) {
  const errorMessages = {};
  
  Object.keys(errors).forEach(field => {
    errorMessages[field] = errors[field][0]; // Get first error message
  });
  
  return errorMessages;
}

// Usage
try {
  const response = await api.createTicket(ticketData);
} catch (error) {
  if (error.response?.status === 422) {
    const fieldErrors = handleValidationErrors(error.response.data.errors);
    // Display errors in form
    displayFormErrors(fieldErrors);
  }
}

React Example:

const [errors, setErrors] = useState({});

const handleSubmit = async (formData) => {
  try {
    await api.createTicket(formData);
    setErrors({});
  } catch (error) {
    if (error.response?.status === 422) {
      const fieldErrors = {};
      Object.keys(error.response.data.errors).forEach(field => {
        fieldErrors[field] = error.response.data.errors[field][0];
      });
      setErrors(fieldErrors);
    }
  }
};

// In JSX
{errors.email && <div className="error">{errors.email}</div>}

Error Handling Examples

JavaScript/TypeScript

class APIError extends Error {
  constructor(message, status, errors = {}) {
    super(message);
    this.name = 'APIError';
    this.status = status;
    this.errors = errors;
  }
}

async function handleAPIRequest(requestFn) {
  try {
    const response = await requestFn();
    return response.data;
  } catch (error) {
    if (error.response) {
      // Server responded with error
      const { status, data } = error.response;
      
      switch (status) {
        case 401:
          // Unauthorized
          localStorage.removeItem('api_token');
          window.location.href = '/login';
          throw new APIError('Please log in again', 401);
          
        case 403:
          // Forbidden
          throw new APIError('You do not have permission', 403);
          
        case 404:
          // Not Found
          throw new APIError(data.message || 'Resource not found', 404);
          
        case 422:
          // Validation Error
          throw new APIError(
            data.message || 'Validation failed',
            422,
            data.errors || {}
          );
          
        case 429:
          // Rate Limited
          const retryAfter = error.response.headers['retry-after'];
          throw new APIError(
            `Rate limit exceeded. Retry after ${retryAfter} seconds`,
            429
          );
          
        default:
          throw new APIError(
            data.message || 'An error occurred',
            status
          );
      }
    } else if (error.request) {
      // Request made but no response
      throw new APIError('Network error. Please check your connection.', 0);
    } else {
      // Error setting up request
      throw new APIError('Request setup error', 0);
    }
  }
}

// Usage
try {
  const tickets = await handleAPIRequest(() => 
    api.get('/tickets')
  );
} catch (error) {
  if (error instanceof APIError) {
    console.error(`API Error (${error.status}):`, error.message);
    if (error.errors) {
      console.error('Field errors:', error.errors);
    }
  }
}

PHP

class APIException extends Exception {
    public $statusCode;
    public $errors;

    public function __construct($message, $statusCode = 400, $errors = []) {
        parent::__construct($message);
        $this->statusCode = $statusCode;
        $this->errors = $errors;
    }
}

function handleAPIRequest($requestFn) {
    try {
        $response = $requestFn();
        return $response;
    } catch (Exception $e) {
        if ($e instanceof APIException) {
            throw $e;
        }
        
        // Handle HTTP errors
        if (method_exists($e, 'getResponse')) {
            $response = $e->getResponse();
            $statusCode = $response->getStatusCode();
            $data = json_decode($response->getBody(), true);
            
            switch ($statusCode) {
                case 401:
                    // Unauthorized
                    throw new APIException('Please log in again', 401);
                    
                case 403:
                    // Forbidden
                    throw new APIException('You do not have permission', 403);
                    
                case 404:
                    // Not Found
                    throw new APIException(
                        $data['message'] ?? 'Resource not found',
                        404
                    );
                    
                case 422:
                    // Validation Error
                    throw new APIException(
                        $data['message'] ?? 'Validation failed',
                        422,
                        $data['errors'] ?? []
                    );
                    
                default:
                    throw new APIException(
                        $data['message'] ?? 'An error occurred',
                        $statusCode
                    );
            }
        }
        
        throw new APIException('Network error', 0);
    }
}

Python

class APIError(Exception):
    def __init__(self, message, status_code=400, errors=None):
        self.message = message
        self.status_code = status_code
        self.errors = errors or {}
        super().__init__(self.message)

def handle_api_request(request_fn):
    try:
        response = request_fn()
        return response.json()
    except requests.exceptions.HTTPError as e:
        status_code = e.response.status_code
        data = e.response.json()
        
        if status_code == 401:
            # Unauthorized
            raise APIError('Please log in again', 401)
        elif status_code == 403:
            # Forbidden
            raise APIError('You do not have permission', 403)
        elif status_code == 404:
            # Not Found
            raise APIError(
                data.get('message', 'Resource not found'),
                404
            )
        elif status_code == 422:
            # Validation Error
            raise APIError(
                data.get('message', 'Validation failed'),
                422,
                data.get('errors', {})
            )
        elif status_code == 429:
            # Rate Limited
            retry_after = e.response.headers.get('Retry-After', '60')
            raise APIError(
                f'Rate limit exceeded. Retry after {retry_after} seconds',
                429
            )
        else:
            raise APIError(
                data.get('message', 'An error occurred'),
                status_code
            )
    except requests.exceptions.RequestException as e:
        raise APIError('Network error', 0)

Best Practices

1. Always Check Response Status

const response = await fetch(url, options);
if (!response.ok) {
  throw new Error(`HTTP error! status: ${response.status}`);
}

2. Provide User-Friendly Messages

const errorMessages = {
  401: 'Please log in to continue',
  403: 'You do not have permission for this action',
  404: 'The requested item was not found',
  422: 'Please check your input and try again',
  429: 'Too many requests. Please wait a moment',
  500: 'Server error. Please try again later',
};

function getUserFriendlyMessage(statusCode) {
  return errorMessages[statusCode] || 'An error occurred';
}

3. Log Errors for Debugging

function logError(error, context) {
  console.error('API Error:', {
    message: error.message,
    status: error.status,
    context: context,
    timestamp: new Date().toISOString(),
  });
  
  // Send to error tracking service
  // errorTrackingService.log(error, context);
}

4. Implement Retry Logic

async function requestWithRetry(url, options, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      const response = await fetch(url, options);
      if (response.ok) return response;
      
      // Don't retry client errors (4xx)
      if (response.status >= 400 && response.status < 500) {
        throw new Error(`Client error: ${response.status}`);
      }
      
      // Retry server errors (5xx)
      if (i < maxRetries - 1) {
        await new Promise(resolve => setTimeout(resolve, 1000 * (i + 1)));
        continue;
      }
      
      throw new Error(`Server error: ${response.status}`);
    } catch (error) {
      if (i === maxRetries - 1) throw error;
    }
  }
}

Troubleshooting

Common Issues

"Unauthenticated" Error

Problem: Token is missing or invalid.

Solution:

  1. Verify token is included in Authorization header
  2. Check token format: Bearer {token}
  3. Re-authenticate to get a new token

"Validation Failed" Error

Problem: Request data doesn't meet validation requirements.

Solution:

  1. Check error messages for each field
  2. Verify required fields are provided
  3. Ensure data types are correct
  4. Review validation rules in documentation

"Too Many Requests" Error

Problem: Rate limit exceeded.

Solution:

  1. Wait for rate limit window to reset
  2. Check Retry-After header
  3. Implement request throttling
  4. Reduce request frequency

Network Errors

Problem: Request fails before reaching server.

Solution:

  1. Check internet connection
  2. Verify API base URL is correct
  3. Check firewall/proxy settings
  4. Test with cURL to isolate issue

Next Steps


For additional support with error handling, contact our API support team.

← All HelpDesk Pro – AI Helpdesk & Customer Support Software with Live Chat documentation

We use cookies to understand how visitors use this site. Cookie Policy