Skip to main content
The Encore SDK provides structured error handling with specific error codes and types. This guide covers all error types and best practices for handling them.

Error Types

EncoreError

All SDK errors conform to this interface:
interface EncoreError {
  code: ErrorCode | string
  message: string
  details?: unknown
  type?: string
  statusCode?: number
}
code
ErrorCode | string
Error code identifying the error type. See Error Codes below.
message
string
Human-readable error message
details
unknown
Additional error details (if available)
type
string
Error type category (if applicable)
statusCode
number
HTTP status code (for API errors)

NotGrantedReason

When presentOffer() doesn’t grant an entitlement, the reason can be:
type NotGrantedReason =
  | 'userClosedModal'
  | 'userClickedOutside'
  | 'userDeclinedLastOffer'
  | 'noOffersAvailable'
  | { type: 'error', error: EncoreError }

Error Codes

ErrorCode Enum

enum ErrorCode {
  // Network errors
  NETWORK_ERROR = 'NETWORK_ERROR',
  TIMEOUT = 'TIMEOUT',
  
  // API errors
  API_ERROR = 'API_ERROR',
  UNAUTHORIZED = 'UNAUTHORIZED',
  NOT_FOUND = 'NOT_FOUND',
  INVALID_REQUEST = 'INVALID_REQUEST',
  
  // Configuration errors
  CONFIGURATION_ERROR = 'CONFIGURATION_ERROR',
  INITIALIZATION_ERROR = 'INITIALIZATION_ERROR',
  
  // Storage errors
  STORAGE_ERROR = 'STORAGE_ERROR',
  
  // Generic
  UNKNOWN_ERROR = 'UNKNOWN_ERROR'
}

Error Code Descriptions

When it occurs: Network connectivity issuesCommon causes:
  • User is offline
  • DNS resolution failed
  • Network request blocked by firewall/proxy
Handling:
try {
  await Encore.refreshEntitlements();
} catch (error) {
  if (error.code === 'NETWORK_ERROR') {
    showMessage('Please check your internet connection');
    retryLater();
  }
}
When it occurs: Request took too long to completeCommon causes:
  • Slow network connection
  • Server overload
  • Large payload
Handling:
try {
  await Encore.presentOffer();
} catch (error) {
  if (error.code === 'TIMEOUT') {
    showMessage('Request timed out. Please try again.');
    logTimeout(error);
  }
}
When it occurs: API returned an error responseCommon causes:
  • Server-side error
  • Invalid request format
  • Rate limiting
Handling:
try {
  await Encore.refreshEntitlements();
} catch (error) {
  if (error.code === 'API_ERROR') {
    console.error('API error:', error.message);
    if (error.statusCode === 429) {
      showMessage('Too many requests. Please wait.');
    }
  }
}
When it occurs: Invalid API key or authentication failedCommon causes:
  • Wrong API key
  • Expired API key
  • Revoked API key
Handling:
try {
  await Encore.presentOffer();
} catch (error) {
  if (error.code === 'UNAUTHORIZED') {
    console.error('Invalid API key');
    contactSupport();
  }
}
When it occurs: SDK configuration is invalidCommon causes:
  • Missing required configuration
  • Invalid configuration values
  • Configuration called multiple times
Handling:
try {
  Encore.configure({ apiKey: '' });  // Empty key
} catch (error) {
  if (error.code === 'CONFIGURATION_ERROR') {
    console.error('Configuration error:', error.message);
    // Fix configuration
  }
}
When it occurs: localStorage/sessionStorage operations failedCommon causes:
  • Browser privacy settings
  • Storage quota exceeded
  • Private/incognito mode restrictions
Handling:
try {
  Encore.identify('user-123');
} catch (error) {
  if (error.code === 'STORAGE_ERROR') {
    showMessage('Storage unavailable. Some features may not work.');
    fallbackToSessionStorage();
  }
}

Handling Errors

Try-Catch Pattern

import Encore from '@encore/web-sdk';

try {
  const result = await Encore.presentOffer();
  
  if (result.granted) {
    unlockFeature();
  }
} catch (error) {
  console.error('Error presenting offer:', error);
  
  // Handle specific error codes
  switch (error.code) {
    case 'NETWORK_ERROR':
      showMessage('Please check your connection');
      break;
    case 'UNAUTHORIZED':
      contactSupport();
      break;
    default:
      showGenericError();
  }
}

Callback Error Handling

await Encore.presentOffer({
  onGranted: (entitlement) => {
    unlockFeature();
  },
  onNotGranted: (reason) => {
    if (typeof reason === 'object' && reason.type === 'error') {
      handleError(reason.error);
    }
  },
  onError: (error) => {
    console.error('Presentation error:', error);
    showErrorMessage(error.message);
  }
});

Graceful Degradation

async function safeRefreshEntitlements() {
  try {
    await Encore.refreshEntitlements();
  } catch (error) {
    console.error('Refresh failed:', error);
    // Continue without refresh - use cached data
  }
}

Common Error Scenarios

Network Errors

async function handleNetworkError() {
  try {
    await Encore.presentOffer();
  } catch (error) {
    if (error.code === 'NETWORK_ERROR') {
      // Show retry option
      showRetryButton(() => handleNetworkError());
      
      // Queue for later
      queueOperation('presentOffer');
      
      // Use cached data
      const cachedData = getCachedEntitlements();
      if (cachedData) {
        useCachedData(cachedData);
      }
    }
  }
}

API Errors

async function handleAPIError() {
  try {
    await Encore.refreshEntitlements();
  } catch (error) {
    if (error.code === 'API_ERROR') {
      // Log for debugging
      logError(error);
      
      // Check status code
      if (error.statusCode === 503) {
        showMessage('Service temporarily unavailable');
      } else if (error.statusCode === 429) {
        showMessage('Too many requests. Please wait.');
      }
      
      // Retry with backoff
      retryWithBackoff(() => Encore.refreshEntitlements());
    }
  }
}

Configuration Errors

function initializeSDK(apiKey) {
  try {
    Encore.configure({ apiKey });
  } catch (error) {
    if (error.code === 'CONFIGURATION_ERROR') {
      console.error('Configuration failed:', error.message);
      
      // Show error to developer
      if (process.env.NODE_ENV === 'development') {
        showDevError(error);
      }
      
      // Fallback to default config
      Encore.configure({ apiKey: process.env.FALLBACK_KEY });
    }
  }
}

Framework Error Handling

  • React
  • Vue
  • Angular
import { useState } from 'react';
import Encore from '@encore/web-sdk';

function OfferButton() {
  const [error, setError] = useState(null);
  const [loading, setLoading] = useState(false);
  
  const handleClick = async () => {
    setError(null);
    setLoading(true);
    
    try {
      const result = await Encore.presentOffer();
      // Handle success
    } catch (err) {
      setError(err);
      console.error('Error:', err);
    } finally {
      setLoading(false);
    }
  };
  
  return (
    <div>
      <button onClick={handleClick} disabled={loading}>
        Get Premium
      </button>
      {error && (
        <div className="error">
          {getErrorMessage(error)}
        </div>
      )}
    </div>
  );
}

function getErrorMessage(error) {
  switch (error.code) {
    case 'NETWORK_ERROR':
      return 'Connection error. Please try again.';
    case 'UNAUTHORIZED':
      return 'Authentication failed. Please contact support.';
    default:
      return 'Something went wrong. Please try again.';
  }
}

Best Practices

1. Always Handle Errors

// Good: Error handling
try {
  await Encore.presentOffer();
} catch (error) {
  handleError(error);
}

// Avoid: No error handling
await Encore.presentOffer();  // ❌ Unhandled rejection

2. Provide User Feedback

// Good: User-friendly messages
try {
  await Encore.refreshEntitlements();
} catch (error) {
  showMessage(getUserFriendlyMessage(error));
}

// Avoid: Technical messages
catch (error) {
  alert(error.message);  // ❌ "API_ERROR: 500"
}

3. Log for Debugging

// Good: Comprehensive logging
try {
  await Encore.presentOffer();
} catch (error) {
  console.error('Error details:', {
    code: error.code,
    message: error.message,
    details: error.details
  });
  trackError(error);
}

4. Graceful Degradation

// Good: Continue with cached data
try {
  await Encore.refreshEntitlements();
} catch (error) {
  console.warn('Using cached entitlements');
  // App continues to work
}

Complete Error Handling Example

import Encore from '@encore/web-sdk';

class ErrorHandler {
  async presentOfferWithErrorHandling() {
    try {
      const result = await Encore.presentOffer();
      
      if (result.granted) {
        return { success: true, entitlement: result.entitlement };
      }
      
      return { success: false, reason: result.reason };
    } catch (error) {
      return this.handleError(error);
    }
  }
  
  handleError(error) {
    // Log error
    console.error('Encore error:', error);
    this.trackError(error);
    
    // Handle specific errors
    switch (error.code) {
      case 'NETWORK_ERROR':
        this.showMessage('Connection error. Please check your internet.');
        return { success: false, error: 'network' };
      
      case 'UNAUTHORIZED':
        this.showMessage('Authentication failed. Please contact support.');
        this.contactSupport(error);
        return { success: false, error: 'auth' };
      
      case 'TIMEOUT':
        this.showMessage('Request timed out. Please try again.');
        return { success: false, error: 'timeout' };
      
      default:
        this.showMessage('Something went wrong. Please try again.');
        return { success: false, error: 'unknown' };
    }
  }
  
  showMessage(message) {
    // Show user-friendly message
    console.log(message);
  }
  
  trackError(error) {
    // Send to analytics/monitoring
    if (window.analytics) {
      analytics.track('encore_error', {
        code: error.code,
        message: error.message
      });
    }
  }
  
  contactSupport(error) {
    // Notify support team
    console.error('Critical error:', error);
  }
}

Next Steps