or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

cancellation.mddata-transformation.mderror-handling.mdheaders.mdhttp-client.mdindex.mdinstance-management.mdinterceptors.md
tile.json

error-handling.mddocs/

Error Handling

Structured error handling with detailed error information, error codes, and type checking utilities for robust application error management.

Capabilities

AxiosError Class

Main error class extending native Error with detailed context about failed requests.

/**
 * Axios-specific error with request/response context
 */
class AxiosError<T = unknown, D = any> extends Error {
  constructor(
    message?: string,
    code?: string,
    config?: InternalAxiosRequestConfig<D>,
    request?: any,
    response?: AxiosResponse<T, D>
  );

  /** Request configuration that caused the error */
  config?: InternalAxiosRequestConfig<D>;
  /** Error code string */
  code?: string;
  /** Request object (XMLHttpRequest, IncomingMessage, etc.) */
  request?: any;
  /** Response object if server responded */
  response?: AxiosResponse<T, D>;
  /** Always true for AxiosError instances */
  isAxiosError: boolean;
  /** HTTP status code if available */
  status?: number;
  /** Underlying error cause */
  cause?: Error;
  
  /** Serialize error to JSON object */
  toJSON(): object;
}

Usage Examples:

import axios from "axios";

try {
  const response = await axios.get("https://api.example.com/users");
} catch (error) {
  if (axios.isAxiosError(error)) {
    console.log("Error message:", error.message);
    console.log("Error code:", error.code);
    console.log("Request URL:", error.config?.url);
    console.log("HTTP status:", error.response?.status);
    console.log("Response data:", error.response?.data);
    
    // Serialize for logging
    console.log("Full error:", error.toJSON());
  }
}

Error Code Constants

Predefined error codes for common failure scenarios.

// Network and connection errors
static readonly ERR_NETWORK = "ERR_NETWORK";
static readonly ECONNABORTED = "ECONNABORTED";
static readonly ETIMEDOUT = "ETIMEDOUT";

// Request/Response errors
static readonly ERR_BAD_REQUEST = "ERR_BAD_REQUEST";
static readonly ERR_BAD_RESPONSE = "ERR_BAD_RESPONSE";

// Configuration errors
static readonly ERR_BAD_OPTION = "ERR_BAD_OPTION";
static readonly ERR_BAD_OPTION_VALUE = "ERR_BAD_OPTION_VALUE";

// Feature/Support errors
static readonly ERR_NOT_SUPPORT = "ERR_NOT_SUPPORT";
static readonly ERR_DEPRECATED = "ERR_DEPRECATED";

// URL errors
static readonly ERR_INVALID_URL = "ERR_INVALID_URL";

// Cancellation errors
static readonly ERR_CANCELED = "ERR_CANCELED";

// Redirect errors
static readonly ERR_FR_TOO_MANY_REDIRECTS = "ERR_FR_TOO_MANY_REDIRECTS";

Usage Examples:

try {
  const response = await axios.get(url, { timeout: 5000 });
} catch (error) {
  if (axios.isAxiosError(error)) {
    switch (error.code) {
      case axios.AxiosError.ETIMEDOUT:
        console.log("Request timed out");
        break;
      case axios.AxiosError.ERR_NETWORK:
        console.log("Network error occurred");
        break;
      case axios.AxiosError.ERR_BAD_REQUEST:
        console.log("Bad request configuration");
        break;
      case axios.AxiosError.ERR_CANCELED:
        console.log("Request was canceled");
        break;
      default:
        console.log("Unknown error:", error.code);
    }
  }
}

Error Factory Method

Create AxiosError instances from existing errors.

/**
 * Create AxiosError from existing error
 * @param error - Original error object
 * @param code - Error code to assign
 * @param config - Request configuration
 * @param request - Request object
 * @param response - Response object
 * @param customProps - Additional properties
 * @returns New AxiosError instance
 */
static AxiosError.from<T = unknown, D = any>(
  error: Error | unknown,
  code?: string,
  config?: InternalAxiosRequestConfig<D>,
  request?: any,
  response?: AxiosResponse<T, D>,
  customProps?: object
): AxiosError<T, D>;

Usage Examples:

// Convert generic error to AxiosError
try {
  // Some operation that might throw
  throw new Error("Something went wrong");
} catch (originalError) {
  const axiosError = axios.AxiosError.from(
    originalError,
    "CUSTOM_ERROR",
    config,
    request,
    response,
    { customProperty: "additional context" }
  );
  
  throw axiosError;
}

CanceledError Class

Specific error type for canceled requests.

/**
 * Error thrown when request is canceled
 */
class CanceledError<T> extends AxiosError<T> {
  constructor(message?: string, config?: InternalAxiosRequestConfig, request?: any);
}

// Legacy alias for backward compatibility
const Cancel = CanceledError;

Error Type Checking

Utility functions to identify different types of errors.

/**
 * Check if error is an AxiosError instance
 * @param payload - Value to check
 * @returns True if payload is AxiosError
 */
axios.isAxiosError<T = any, D = any>(payload: any): payload is AxiosError<T, D>;

/**
 * Check if error is due to request cancellation
 * @param value - Value to check
 * @returns True if value represents cancellation
 */
axios.isCancel(value: any): value is Cancel;

Usage Examples:

try {
  const response = await axios.get(url);
} catch (error) {
  if (axios.isCancel(error)) {
    console.log("Request was canceled:", error.message);
    return; // Handle cancellation gracefully
  }
  
  if (axios.isAxiosError(error)) {
    // Handle different HTTP status codes
    if (error.response) {
      switch (error.response.status) {
        case 400:
          console.log("Bad request:", error.response.data);
          break;
        case 401:
          console.log("Unauthorized - redirect to login");
          window.location.href = "/login";
          break;
        case 403:
          console.log("Forbidden - insufficient permissions");
          break;
        case 404:
          console.log("Resource not found");
          break;
        case 429:
          console.log("Rate limited - retry later");
          break;
        case 500:
        case 502:
        case 503:
        case 504:
          console.log("Server error - retry or show maintenance page");
          break;
        default:
          console.log("HTTP error:", error.response.status);
      }
    } else if (error.request) {
      console.log("No response received:", error.message);
    } else {
      console.log("Request setup error:", error.message);
    }
  } else {
    console.log("Unknown error:", error);
  }
}

Error Response Structure

Structure of error responses when server returns an error.

interface AxiosResponse<T = any, D = any> {
  /** Response data (error details from server) */
  data: T;
  /** HTTP status code */
  status: number;
  /** HTTP status message */
  statusText: string;
  /** Response headers */
  headers: RawAxiosResponseHeaders | AxiosResponseHeaders;
  /** Request configuration */
  config: InternalAxiosRequestConfig<D>;
  /** Native request object */
  request?: any;
}

Usage Examples:

try {
  await axios.post("/api/users", userData);
} catch (error) {
  if (axios.isAxiosError(error) && error.response) {
    // Server responded with error status
    const { status, data, headers } = error.response;
    
    console.log("Status:", status);
    console.log("Error data:", data);
    
    // Handle API error responses
    if (data.errors) {
      // Validation errors
      data.errors.forEach(err => {
        console.log(`${err.field}: ${err.message}`);
      });
    } else if (data.message) {
      // Simple error message
      console.log("Error:", data.message);
    }
    
    // Check error-specific headers
    const retryAfter = headers["retry-after"];
    if (status === 429 && retryAfter) {
      console.log(`Rate limited. Retry after ${retryAfter} seconds`);
    }
  }
}

Global Error Handling Patterns

Common patterns for handling errors application-wide.

Usage Examples:

// Global error interceptor
axios.interceptors.response.use(
  (response) => response,
  (error) => {
    if (axios.isAxiosError(error)) {
      // Log all axios errors
      console.error("Axios Error:", {
        url: error.config?.url,
        method: error.config?.method,
        status: error.response?.status,
        message: error.message,
        data: error.response?.data
      });
      
      // Handle specific error cases
      if (error.response?.status === 401) {
        // Redirect to login
        localStorage.removeItem("authToken");
        window.location.href = "/login";
        return Promise.reject(error);
      }
      
      if (error.response?.status >= 500) {
        // Show generic server error message
        showNotification("Server error occurred. Please try again later.", "error");
      }
    }
    
    return Promise.reject(error);
  }
);

// Error boundary for React applications
class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false, error: null };
  }
  
  static getDerivedStateFromError(error) {
    return { hasError: true, error };
  }
  
  componentDidCatch(error, errorInfo) {
    if (axios.isAxiosError(error)) {
      // Send axios errors to monitoring service
      sendToMonitoring({
        type: "axios_error",
        url: error.config?.url,
        status: error.response?.status,
        message: error.message,
        stack: error.stack
      });
    }
  }
  
  render() {
    if (this.state.hasError) {
      return <ErrorFallback error={this.state.error} />;
    }
    
    return this.props.children;
  }
}

// Retry with exponential backoff
async function retryRequest(requestFn, maxRetries = 3) {
  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      return await requestFn();
    } catch (error) {
      if (axios.isAxiosError(error)) {
        const shouldRetry = error.response?.status >= 500 || 
                           error.code === "ECONNABORTED" ||
                           error.code === "ERR_NETWORK";
        
        if (shouldRetry && attempt < maxRetries) {
          const delay = Math.pow(2, attempt) * 1000; // Exponential backoff
          console.log(`Request failed, retrying in ${delay}ms (attempt ${attempt}/${maxRetries})`);
          await new Promise(resolve => setTimeout(resolve, delay));
          continue;
        }
      }
      
      throw error; // Re-throw if not retryable or max retries reached
    }
  }
}

// Usage
try {
  const response = await retryRequest(() => 
    axios.get("https://unreliable-api.example.com/data")
  );
  console.log(response.data);
} catch (error) {
  console.log("Request failed after retries:", error.message);
}

Custom Error Classes

Extend AxiosError for application-specific error handling.

Usage Examples:

// Custom error for API validation errors
class ValidationError extends axios.AxiosError {
  constructor(errors, config, request, response) {
    super("Validation failed", "VALIDATION_ERROR", config, request, response);
    this.name = "ValidationError";
    this.validationErrors = errors;
  }
  
  getFieldErrors() {
    return this.validationErrors || [];
  }
}

// Custom error for business logic errors
class BusinessLogicError extends axios.AxiosError {
  constructor(businessCode, message, config, request, response) {
    super(message, "BUSINESS_ERROR", config, request, response);
    this.name = "BusinessLogicError";
    this.businessCode = businessCode;
  }
}

// Error factory
function createAppError(axiosError) {
  if (axiosError.response?.status === 422) {
    return new ValidationError(
      axiosError.response.data.errors,
      axiosError.config,
      axiosError.request,
      axiosError.response
    );
  }
  
  if (axiosError.response?.data?.businessCode) {
    return new BusinessLogicError(
      axiosError.response.data.businessCode,
      axiosError.response.data.message,
      axiosError.config,
      axiosError.request,
      axiosError.response
    );
  }
  
  return axiosError; // Return original error
}

// Usage in interceptor
axios.interceptors.response.use(
  (response) => response,
  (error) => {
    if (axios.isAxiosError(error)) {
      throw createAppError(error);
    }
    throw error;
  }
);