The SDK provides consistent, type-safe error handling across all API operations with automatic recovery mechanisms and structured error responses.

The { data, error } Pattern

All SDK methods return a consistent object with data and error properties, allowing for easy, type-safe error handling.

Type-Safe Error Handling

const { data, error } = await client.catalog.getProduct('product-id');

if (data) {
  // ✅ TypeScript knows data.content is a Product
  console.log(data.content.name);
  console.log(data.content.selling_price);
} else if (error) {
  // ✅ TypeScript knows error is ApiErrorResponse
  console.error(error.message);
  console.error(error.code);
  
  // Handle specific error types
  switch (error.code) {
    case 'NOT_FOUND':
      showProductNotFound();
      break;
    case 'VALIDATION_ERROR':
      showValidationError(error.details);
      break;
    default:
      showGenericError(error.message);
  }
}

Error Types & Codes

The SDK provides structured error responses with consistent codes:

Automatic Error Recovery

Token Refresh

The SDK automatically handles token expiry:
// This request may trigger automatic token refresh
const { data, error } = await client.customer.retrieveCustomerDetail('user-id');

// No manual token handling needed!
if (data) {
  console.log(data.content.email);
}

Authentication Recovery

The SDK automatically handles token refresh and authentication recovery:
// SDK handles token refresh transparently
const client = new StorefrontSDK({
  storeId: 'your-store-id',
  apiKey: 'your-api-key',
  tokenStorage: new BrowserTokenStorage() // Enables automatic token management
});

Error Handling Patterns

Component Error Boundaries

// React error boundary for SDK errors
class SDKErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false, error: null };
  }
  
  static getDerivedStateFromError(error) {
    return { hasError: true, error };
  }
  
  render() {
    if (this.state.hasError) {
      // Handle SDK-specific errors
      if (this.state.error?.code === 'NETWORK_ERROR') {
        return <NetworkErrorPage />;
      }
      
      return <GenericErrorPage error={this.state.error} />;
    }
    
    return this.props.children;
  }
}

Form Validation

// Handle validation errors in forms
async function submitForm(formData) {
  const { data, error } = await client.customer.updateCustomerDetail('user-id', formData);
  
  if (error) {
    if (error.code === 'VALIDATION_ERROR') {
      // Display field-specific errors
      setFieldErrors(error.details);
      return;
    }
    
    // Handle other errors
    setGeneralError(error.message);
  }
  
  // Success
  showSuccessMessage();
}

Global Error Handler

// Global error handler for SDK operations
const handleSDKError = (error: ApiErrorResponse) => {
  // Log to monitoring service
  errorLogger.log(error);
  
  // Show user-friendly messages
  switch (error.code) {
    case 'NETWORK_ERROR':
      toast.error('Connection problem. Please check your internet.');
      break;
    case 'UNAUTHORIZED':
      toast.error('Session expired. Please log in again.');
      redirectToLogin();
      break;
    case 'SERVER_ERROR':
      toast.error('Server error. Please try again later.');
      break;
    default:
      toast.error(error.message || 'Something went wrong.');
  }
};

// Use in SDK operations
const { data, error } = await client.catalog.listProducts();
if (error) {
  handleSDKError(error);
}

Error Monitoring

Custom Error Logging

const client = new StorefrontSDK({
  storeId: 'your-store-id',
  apiKey: 'your-api-key',
  debug: true,
  logger: (level, message, data) => {
    if (level === 'error') {
      // Send to error tracking service
      Sentry.captureException(new Error(message), {
        extra: data,
        tags: { source: 'storefront-sdk' }
      });
    }
  }
});

Error Analytics

// Track error patterns
const trackError = (error: ApiErrorResponse, context: string) => {
  analytics.track('sdk_error', {
    error_code: error.code,
    error_message: error.message,
    context,
    timestamp: new Date().toISOString(),
    user_agent: navigator.userAgent
  });
};

// Usage
const { data, error } = await client.order.createOrder(orderData);
if (error) {
  trackError(error, 'checkout_flow');
}

Best Practices

Show User-Friendly Messages

Avoid exposing raw API errors to users.

Log Errors for Debugging

Use a monitoring service to track and analyze errors.

Implement Retries Strategically

Use retries for network errors, not for validation or server errors.

Use Error Boundaries

Prevent UI crashes by wrapping components in error boundaries.

Cross-References

The SDK’s error handling builds on top of the patterns described in the Storefront Guides, providing automatic recovery and type safety for a better developer experience.