OS Trading Engine
API Reference
Error Codes & Handling

Error Codes & Handling

Understand Nexgent API errors and how to handle them in your application.


Error Response Format

All API errors return a consistent JSON structure:

{
  "success": false,
  "error": "Human-readable error message",
  "code": "ERROR_CODE",
  "details": { ... }
}
FieldTypeDescription
successbooleanAlways false for errors
errorstringHuman-readable error message
codestringMachine-readable error code (optional)
detailsobjectAdditional error details (optional)

In development mode, errors also include a stack field with the stack trace.


HTTP Status Codes

Success Codes

CodeMeaningUsage
200OKSuccessful GET, PUT, DELETE
201CreatedSuccessful POST creating a resource

Client Error Codes

CodeMeaningCommon Causes
400Bad RequestInvalid input, validation failure
401UnauthorizedMissing or invalid token
403ForbiddenValid token but insufficient permissions
404Not FoundResource doesn't exist
409ConflictDuplicate resource, constraint violation
423LockedAccount locked due to failed attempts
429Too Many RequestsRate limit exceeded

Server Error Codes

CodeMeaningCommon Causes
500Internal Server ErrorUnexpected server error
502Bad GatewayExternal service failure (Jupiter, Pyth)
503Service UnavailableServer overloaded or maintenance

Error Codes Reference

Authentication Errors

CodeHTTPDescription
AUTHENTICATION_ERROR401Token invalid, expired, or missing
AUTHORIZATION_ERROR403User lacks permission for action

Examples:

// Missing token
{
  "error": "Authorization header required"
}
 
// Invalid token
{
  "error": "Invalid token"
}
 
// Expired token
{
  "error": "Token expired"
}
 
// Blacklisted token (after logout)
{
  "error": "Token has been revoked"
}
 
// Wrong token type
{
  "error": "Invalid token type"
}

Validation Errors

CodeHTTPDescription
VALIDATION_ERROR400Request validation failed

Examples:

// Missing required field
{
  "error": "Name is required"
}
 
// Invalid format
{
  "error": "Invalid agent ID format"
}
 
// Out of range
{
  "error": "Signal strength must be between 1 and 5"
}
 
// Invalid enum value
{
  "error": "Trading mode must be either 'simulation' or 'live'"
}
 
// Password too weak
{
  "error": "Password must contain at least one uppercase letter, one lowercase letter, one number, and one special character"
}

Resource Errors

CodeHTTPDescription
NOT_FOUND404Requested resource not found
CONFLICT409Resource conflict (duplicate)

Examples:

// Resource not found
{
  "error": "Agent not found"
}
 
// Email already exists
{
  "error": "Email already registered"
}
 
// Duplicate API key name
{
  "error": "API key name already exists"
}

Trading Errors

CodeHTTPDescription
TRADING_ERROR400Trading operation failed

Examples:

// Insufficient balance
{
  "error": "Insufficient SOL balance",
  "code": "TRADING_ERROR",
  "details": {
    "required": 1.5,
    "available": 0.5
  }
}
 
// Position not found
{
  "error": "Position not found",
  "code": "TRADING_ERROR"
}
 
// Invalid slippage
{
  "error": "Slippage exceeds maximum allowed",
  "details": {
    "requested": 5000,
    "maximum": 1000
  }
}

External Service Errors

CodeHTTPDescription
EXTERNAL_SERVICE_ERROR502External dependency failed

Examples:

// Jupiter API failure
{
  "error": "Jupiter error: Failed to get quote",
  "code": "EXTERNAL_SERVICE_ERROR",
  "details": {
    "service": "jupiter",
    "statusCode": 500
  }
}
 
// Price feed unavailable
{
  "error": "DexScreener error: Rate limited",
  "code": "EXTERNAL_SERVICE_ERROR"
}

Rate Limiting Errors

HTTPDescription
429Too many requests

Response:

{
  "error": "Too many requests. Please try again later.",
  "retryAfter": 45
}
FieldTypeDescription
retryAfternumberSeconds until rate limit resets

Rate Limits:

EndpointLimitWindow
POST /trading-signals120 requests1 minute
GET /data-sources30 requests1 minute
/wallets/*5 requests1 minute

Account Lockout

HTTPDescription
423Account locked

Response:

{
  "error": "Account is locked. Please try again later.",
  "lockedUntil": "2025-01-20T10:45:00.000Z"
}

Lockout Rules:

  • Triggered after 5 failed login attempts
  • Duration: 15 minutes
  • Resets after successful login

Handling Errors

JavaScript/TypeScript

async function apiRequest(url: string, options: RequestInit) {
  const response = await fetch(url, {
    ...options,
    headers: {
      'Content-Type': 'application/json',
      'Authorization': `Bearer ${getAccessToken()}`,
      ...options.headers,
    },
  });
 
  if (!response.ok) {
    const error = await response.json();
    
    switch (response.status) {
      case 401:
        // Token expired - try refresh
        if (error.error === 'Token expired') {
          await refreshTokens();
          return apiRequest(url, options); // Retry
        }
        // Invalid token - redirect to login
        redirectToLogin();
        break;
        
      case 403:
        // Permission denied
        showError('You do not have permission for this action');
        break;
        
      case 404:
        // Resource not found
        showError(error.error || 'Resource not found');
        break;
        
      case 429:
        // Rate limited
        const retryAfter = error.retryAfter || 60;
        showError(`Rate limited. Retry in ${retryAfter} seconds`);
        break;
        
      case 502:
        // External service error
        showError('Service temporarily unavailable. Please try again.');
        break;
        
      default:
        // Generic error
        showError(error.error || 'An error occurred');
    }
    
    throw new ApiError(error.error, response.status, error.code, error.details);
  }
 
  return response.json();
}
 
class ApiError extends Error {
  constructor(
    message: string,
    public statusCode: number,
    public code?: string,
    public details?: any
  ) {
    super(message);
    this.name = 'ApiError';
  }
}

React Query Error Handling

import { QueryClient } from '@tanstack/react-query';
 
const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
      retry: (failureCount, error) => {
        // Don't retry on 4xx errors (except 429)
        if (error instanceof ApiError) {
          if (error.statusCode >= 400 && error.statusCode < 500 && error.statusCode !== 429) {
            return false;
          }
        }
        return failureCount < 3;
      },
      retryDelay: (attemptIndex) => Math.min(1000 * 2 ** attemptIndex, 30000),
    },
    mutations: {
      onError: (error) => {
        if (error instanceof ApiError) {
          // Handle specific errors
          if (error.statusCode === 401) {
            // Session expired
            signOut();
          }
        }
      },
    },
  },
});

Python Error Handling

import requests
from dataclasses import dataclass
from typing import Optional, Any
 
@dataclass
class ApiError(Exception):
    message: str
    status_code: int
    code: Optional[str] = None
    details: Optional[Any] = None
 
def api_request(method: str, url: str, **kwargs) -> dict:
    headers = kwargs.pop('headers', {})
    headers['Content-Type'] = 'application/json'
    headers['Authorization'] = f'Bearer {get_access_token()}'
    
    response = requests.request(method, url, headers=headers, **kwargs)
    
    if not response.ok:
        error_data = response.json()
        
        if response.status_code == 401 and error_data.get('error') == 'Token expired':
            refresh_tokens()
            return api_request(method, url, **kwargs)
        
        raise ApiError(
            message=error_data.get('error', 'Unknown error'),
            status_code=response.status_code,
            code=error_data.get('code'),
            details=error_data.get('details'),
        )
    
    return response.json()
 
# Usage
try:
    agent = api_request('GET', f'{BASE_URL}/api/v1/agents/{agent_id}')
except ApiError as e:
    if e.status_code == 404:
        print(f"Agent not found: {e.message}")
    elif e.status_code == 429:
        print("Rate limited, waiting...")
    else:
        print(f"Error: {e.message}")

Best Practices

1. Always Check Status Codes

Don't assume success. Check the HTTP status code before parsing the response body.

2. Handle Token Expiration Gracefully

Implement automatic token refresh to avoid disrupting user experience.

3. Show User-Friendly Messages

Map technical errors to user-friendly messages:

const errorMessages: Record<string, string> = {
  'AUTHENTICATION_ERROR': 'Please log in again',
  'AUTHORIZATION_ERROR': 'You don\'t have permission for this action',
  'NOT_FOUND': 'The requested item was not found',
  'TRADING_ERROR': 'Trade could not be completed',
  'EXTERNAL_SERVICE_ERROR': 'Service temporarily unavailable',
};

4. Log Errors for Debugging

Log errors with context for debugging:

console.error('API Error:', {
  url: response.url,
  status: response.status,
  error: error.error,
  code: error.code,
  details: error.details,
});

5. Implement Retry Logic

For transient errors (5xx, 429), implement exponential backoff:

async function retryWithBackoff(fn: () => Promise<any>, maxRetries = 3) {
  for (let attempt = 0; attempt < maxRetries; attempt++) {
    try {
      return await fn();
    } catch (error) {
      if (attempt === maxRetries - 1) throw error;
      
      const isRetryable = error instanceof ApiError && 
        (error.statusCode >= 500 || error.statusCode === 429);
      
      if (!isRetryable) throw error;
      
      const delay = Math.min(1000 * Math.pow(2, attempt), 10000);
      await new Promise(r => setTimeout(r, delay));
    }
  }
}