Skip to content

Error Handling

Learn how to handle errors gracefully when working with the Sherpai Partner API.

Overview

The Sherpai Partner API returns standard HTTP status codes to indicate the success or failure of requests. This guide covers common error scenarios and how to handle them in your applications.

HTTP Status Codes

Success Codes

Code Description When Used
200 OK Successful GET, PUT, PATCH requests
201 Created Successful POST requests that create resources
204 No Content Successful DELETE requests

Client Error Codes

Code Description Common Causes
400 Bad Request Invalid request format or parameters
401 Unauthorized Missing or invalid authentication token
403 Forbidden Valid token but insufficient permissions
404 Not Found Resource does not exist
422 Unprocessable Entity Request validation failed
429 Too Many Requests Rate limit exceeded

Server Error Codes

Code Description Action
500 Internal Server Error Retry request after delay
502 Bad Gateway Temporary issue, retry with backoff
503 Service Unavailable Service temporarily down

Error Response Format

All errors return a consistent JSON format with detailed information:

Standard Error Response

{
  "detail": "Human-readable error message",
  "error_code": "ERROR_CODE",
  "status_code": 400,
  "status": "error",
  "timestamp": "2024-01-01T12:00:00Z",
  "request_id": "abc123-def456-ghi789"
}

Validation Error Response (422)

For validation errors, additional field-level details are provided:

{
  "detail": [
    {
      "loc": ["body", "email"],
      "msg": "field required",
      "type": "value_error.missing",
      "ctx": {}
    },
    {
      "loc": ["query", "brand_id"],
      "msg": "ensure this value is greater than or equal to 1",
      "type": "value_error.number.not_ge",
      "ctx": {"limit_value": 1}
    }
  ],
  "error_code": "VALIDATION_ERROR",
  "status_code": 422,
  "status": "error",
  "timestamp": "2024-01-01T12:00:00Z",
  "request_id": "abc123-def456-ghi789"
}

Error Response Fields

Field Type Description
detail string or array Human-readable error message(s)
error_code string Machine-readable error code (see Error Codes)
status_code integer HTTP status code
status string Always "error" for error responses
timestamp string ISO 8601 timestamp of the error
request_id string Unique request identifier for support
retry_after integer Seconds to wait before retrying (for 429 errors)

Error Codes

The API uses standardized error codes for programmatic error handling:

Authentication Errors

  • INVALID_CREDENTIALS - Missing or invalid credentials
  • TOKEN_INVALID - Token format is invalid
  • TOKEN_EXPIRED - Token has expired
  • USER_DISABLED - User account is disabled
  • TOO_MANY_ATTEMPTS - Too many failed login attempts

Authorization Errors

  • INSUFFICIENT_PERMISSIONS - User lacks required permissions
  • ROLE_REQUIRED - Specific role required
  • COMPANY_ACCESS_DENIED - Access denied to company/brand

Validation Errors

  • VALIDATION_ERROR - General validation error
  • INVALID_DATE_FORMAT - Invalid date format
  • INVALID_PLATFORM - Invalid platform identifier
  • INVALID_METRICS - Invalid metrics parameter
  • INVALID_ORDER_BY - Invalid order_by parameter
  • INVALID_CURSOR - Invalid pagination cursor
  • REQUIRED_FIELD_MISSING - Required field is missing
  • VALUE_OUT_OF_RANGE - Value outside allowed range

Resource Errors

  • BRAND_NOT_FOUND - Brand does not exist
  • POST_NOT_FOUND - Post does not exist
  • USER_NOT_FOUND - User does not exist
  • ACCOUNT_NOT_FOUND - Account does not exist

Rate Limiting

  • RATE_LIMIT_EXCEEDED - Rate limit exceeded
  • QUOTA_EXCEEDED - Quota exceeded

Server Errors

  • INTERNAL_SERVER_ERROR - Internal server error
  • SERVICE_UNAVAILABLE - Service temporarily unavailable
  • DATABASE_ERROR - Database operation failed
  • FIREBASE_ERROR - Firebase service error
  • SOCIAL_MEDIA_API_ERROR - External social media API error

Common Error Scenarios

Authentication Errors

Missing Token

curl https://partner-api.sherp.ai/me

Response:

{
  "detail":"Authentication required. Please provide a valid Bearer token in the Authorization header.","error_code":"INVALID_CREDENTIALS","status_code":401,"status":"error","timestamp":"2025-11-12T14:09:16.804787Z","request_id":"d90abe92-da54-4e51-afe5-5e256ba94858"
}

Invalid Token

curl -H "Authorization: Bearer invalid_token" \
  https://partner-api.sherp.ai/me

Response:

{
  "detail":"Authentication error: Invalid authentication token format. Please check your credentials.. Please try again or contact support if the issue persists.","error_code":"TOKEN_INVALID","status_code":401,"status":"error","timestamp":"2025-11-12T14:08:14.373052Z","request_id":"af9dd27e-2b22-4f82-b354-098d275e89b9"
}

Expired Token

{
  "detail":"Your session has expired. Please log in again.","error_code":"TOKEN_EXPIRED","status_code":401,"status":"error","timestamp":"2025-11-12T14:09:39.617970Z","request_id":"bbc01148-4ded-4bc2-8b66-ff9d21977c59"
}

Solution: Re-authenticate to get a new token.

Validation Errors

Missing Required Fields

curl -X POST https://partner-api.sherp.ai/auth/login \
  -H "Content-Type: application/json" \
  -d '{}'

Response:

{
  "detail": [
    {
      "loc": ["body", "email"],
      "msg": "field required",
      "type": "value_error.missing"
    },
    {
      "loc": ["body", "password"],
      "msg": "field required",
      "type": "value_error.missing"
    }
  ]
}

Invalid Parameter Values

curl -H "Authorization: Bearer YOUR_TOKEN" \
  "https://partner-api.sherp.ai/dashboard/?brand_id=0"

Response:

{
  "detail": [
    {
      "loc": ["query", "brand_id"],
      "msg": "ensure this value is greater than or equal to 1",
      "type": "value_error.number.not_ge"
    }
  ]
}

Rate Limiting (429)

When you exceed the rate limit, you'll receive a detailed error response:

Response:

{
  "detail": "Rate limit exceeded. Please wait 2 minutes and 30 seconds before making another request.",
  "error_code": "RATE_LIMIT_EXCEEDED",
  "status_code": 429,
  "status": "error",
  "timestamp": "2024-01-01T12:00:00Z",
  "request_id": "abc123-def456-ghi789",
  "retry_after": 150
}

Response Headers:

X-RateLimit-Limit: 10000
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1704067200
X-Usage-Total: 10000
X-Usage-Period: hourly
Retry-After: 150

Solution: Wait for the time specified in retry_after (seconds) before retrying. Implement exponential backoff for retries.

See Rate Limiting Guide for detailed information.

Retryability Guidance

When encountering errors, use the following guidance to determine whether and how to retry:

Status Code Retry Immediately? Retry with Backoff? Never Retry? Notes
200-299 N/A N/A N/A Success - no retry needed
400 Bad request - fix and retry manually
401 Auth error - re-authenticate first
403 Permission error - check roles
404 Not found - verify resource exists
422 Validation error - fix request
429 Rate limited - use exponential backoff
500 ✅* Server error - retry with backoff
502 Bad gateway - retry with backoff
503 Service unavailable - retry with backoff

*Only retry immediately for idempotent operations (GET requests)

Error Code → Action Mapping

Error Code HTTP Status Retry Strategy Action
TOKEN_EXPIRED 401 Re-authenticate and retry once Get new token via /auth/login
TOKEN_INVALID 401 Do not retry Log error, surface to operator
INVALID_CREDENTIALS 401 Do not retry Escalate to admin / support
RATE_LIMIT_EXCEEDED 429 Retry with exponential backoff Wait for retry_after seconds
INTERNAL_SERVER_ERROR 500 Retry with backoff (idempotent only) Retry after delay
SERVICE_UNAVAILABLE 503 Retry with exponential backoff Wait and retry

Best Practices

1. Implement Retry Logic

For temporary errors (5xx), implement exponential backoff:

import time
import requests
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry

def create_session_with_retries():
    session = requests.Session()
    retry_strategy = Retry(
        total=3,
        backoff_factor=1,
        status_forcelist=[429, 500, 502, 503, 504],
    )
    adapter = HTTPAdapter(max_retries=retry_strategy)
    session.mount("http://", adapter)
    session.mount("https://", adapter)
    return session

2. Handle Authentication Errors

Automatically refresh tokens when they expire:

def make_authenticated_request(url, token):
    headers = {'Authorization': f'Bearer {token}'}
    response = requests.get(url, headers=headers)

    if response.status_code == 401:
        # Token expired, re-authenticate
        new_token = login()
        headers = {'Authorization': f'Bearer {new_token}'}
        response = requests.get(url, headers=headers)

    return response

3. Validate Input Before Sending

Check required fields and formats client-side:

function validateLoginData(email, password) {
  if (!email || !password) {
    throw new Error('Email and password are required');
  }

  if (!email.includes('@')) {
    throw new Error('Invalid email format');
  }

  return { email, password };
}

4. Log Errors for Debugging

import logging

logger = logging.getLogger(__name__)

def handle_api_error(response):
    if response.status_code >= 400:
        logger.error(f"API Error {response.status_code}: {response.text}")

        if response.status_code == 401:
            logger.info("Authentication required")
        elif response.status_code == 429:
            logger.warning("Rate limit exceeded")
        elif response.status_code >= 500:
            logger.error("Server error, retrying...")

    return response

Error Handling Examples

JavaScript/Node.js

async function safeApiCall(url, options = {}) {
  try {
    const response = await fetch(url, options);

    if (!response.ok) {
      const error = await response.json();
      throw new Error(`API Error ${response.status}: ${error.detail}`);
    }

    return await response.json();
  } catch (error) {
    console.error('API call failed:', error.message);

    // Handle specific error types
    if (error.message.includes('401')) {
      // Handle authentication error
      await refreshToken();
      return safeApiCall(url, options); // Retry
    }

    throw error;
  }
}

Python

import requests
from typing import Dict, Any

class APIError(Exception):
    def __init__(self, status_code: int, detail: str):
        self.status_code = status_code
        self.detail = detail
        super().__init__(f"API Error {status_code}: {detail}")

def safe_api_call(url: str, **kwargs) -> Dict[Any, Any]:
    response = requests.get(url, **kwargs)

    if response.status_code >= 400:
        try:
            error_data = response.json()
            detail = error_data.get('detail', 'Unknown error')
        except:
            detail = response.text or 'Unknown error'

        raise APIError(response.status_code, detail)

    return response.json()

# Usage
try:
    data = safe_api_call('https://partner-api.sherp.ai/me',
                        headers={'Authorization': f'Bearer {token}'})
except APIError as e:
    if e.status_code == 401:
        print("Need to re-authenticate")
    elif e.status_code == 429:
        print("Rate limited, waiting...")
        time.sleep(60)
    else:
        print(f"API error: {e.detail}")

Testing Error Scenarios

Unit Tests

import pytest
from unittest.mock import Mock

def test_handle_401_error():
    mock_response = Mock()
    mock_response.status_code = 401
    mock_response.json.return_value = {"detail": "Could not validate credentials"}

    with pytest.raises(APIError) as exc_info:
        handle_response(mock_response)

    assert exc_info.value.status_code == 401
    assert "credentials" in exc_info.value.detail

Next Steps