Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.privacyboost.io/llms.txt

Use this file to discover all available pages before exploring further.

Error Handling

This guide covers error types and handling strategies in the Privacy Boost TypeScript SDK.

Error Types

All SDK errors extend from PrivacyBoostError:
class PrivacyBoostError extends Error {
  code: string;          // Error code for programmatic handling
  message: string;       // Human-readable message
  retryable: boolean;    // Whether the operation can be retried
  cause?: Error;         // Original error if wrapped

  isAuthError(): boolean;     // Check if this is an auth-related error
  isWalletError(): boolean;   // Check if this is a wallet-related error
  hasCode(): boolean;         // Check if a specific error code is set
  static from(error: unknown): PrivacyBoostError; // Wrap unknown errors
}

Error Categories

Configuration Errors

CodeDescription
INVALID_CONFIGInvalid SDK configuration
try {
  await PrivacyBoost.create({
    serverUrl: 'invalid-url', // Will throw
    // ...
  });
} catch (error) {
  if (error.code === 'INVALID_CONFIG') {
    console.log('Please provide valid configuration');
  }
}

Wallet Errors

CodeDescription
TRANSACTION_REJECTEDUser rejected the request
WRONG_NETWORKWrong network
try {
  await sdk.auth.authenticate(adapter);
} catch (error) {
  switch (error.code) {
    case 'TRANSACTION_REJECTED':
      showToast('Authentication cancelled');
      break;
    case 'WRONG_NETWORK':
      showToast('Please switch to the correct network');
      break;
    default:
      showToast('Authentication failed');
  }
}

Authentication Errors

CodeDescription
NOT_AUTHENTICATEDNot authenticated
AUTH_NONCE_EXPIREDAuthentication nonce expired
AUTH_INVALID_SIGNATUREInvalid signature
SESSION_EXPIREDJWT token expired
try {
  await sdk.auth.authenticate(adapter);
} catch (error) {
  if (error.code === 'AUTH_NONCE_EXPIRED') {
    // Retry authentication
    await sdk.auth.authenticate(adapter);
  }
}

Operation Errors

CodeDescription
TRANSFER_PROOF_FAILEDTransfer proof generation failed
try {
  await sdk.vault.shield(params);
} catch (error) {
  switch (error.code) {
    case 'TRANSACTION_REJECTED':
      showError('Transaction cancelled');
      break;
    case 'TRANSFER_PROOF_FAILED':
      showError('Proof generation failed');
      break;
    default:
      showError('Deposit failed: ' + error.message);
  }
}

Network Errors

CodeDescription
TIMEOUTRequest timed out
HTTP_ERRORHTTP request failed
RATE_LIMITEDRate limited
try {
  await sdk.vault.getBalance(tokenAddress);
} catch (error) {
  if (error.code === 'TIMEOUT') {
    // Retry after delay
    await delay(2000);
    await sdk.vault.getBalance(tokenAddress);
  }
}

Proof Errors

CodeDescription
TRANSFER_PROOF_FAILEDFailed to generate transfer proof

Error Handling Patterns

Basic Try-Catch

try {
  await sdk.vault.shield(params);
} catch (error) {
  if (error instanceof PrivacyBoostError) {
    console.log('SDK Error:', error.code, error.message);
  } else {
    console.log('Unknown error:', error);
  }
}

Error Handler Function

function handleError(error: unknown): string {
  if (!(error instanceof PrivacyBoostError)) {
    return 'An unexpected error occurred';
  }

  const messages: Record<string, string> = {
    TRANSACTION_REJECTED: 'Request cancelled',
    SESSION_EXPIRED: 'Session expired, please login again',
    TIMEOUT: 'Request timed out, please try again',
    WRONG_NETWORK: 'Please switch to the correct network',
  };

  return messages[error.code] || error.message;
}

// Usage
try {
  await sdk.vault.transfer(params);
} catch (error) {
  showToast(handleError(error));
}

Retry Logic

async function withRetry<T>(
  operation: () => Promise<T>,
  maxRetries = 3,
  delay = 1000
): Promise<T> {
  let lastError: Error;

  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      return await operation();
    } catch (error) {
      lastError = error;

      // Don't retry user rejections
      if (error.code === 'TRANSACTION_REJECTED') {
        throw error;
      }

      // Retry retryable errors
      if (error.retryable) {
        await new Promise((r) => setTimeout(r, delay * attempt));
        continue;
      }

      throw error;
    }
  }

  throw lastError!;
}

// Usage
const balance = await withRetry(() => sdk.vault.getBalance(token));

Session Refresh

async function withSessionRefresh<T>(
  operation: () => Promise<T>
): Promise<T> {
  try {
    return await operation();
  } catch (error) {
    if (error.code === 'SESSION_EXPIRED') {
      await sdk.auth.authenticate(adapter);
      return await operation();
    }
    throw error;
  }
}

// Usage
const history = await withSessionRefresh(() =>
  sdk.transactions.fetchHistory()
);

React Error Boundary

class PrivacyBoostErrorBoundary extends React.Component<
  { children: React.ReactNode },
  { error: Error | null }
> {
  state = { error: null };

  static getDerivedStateFromError(error: Error) {
    return { error };
  }

  render() {
    if (this.state.error) {
      return (
        <div>
          <h2>Something went wrong</h2>
          <p>{this.state.error.message}</p>
          <button onClick={() => this.setState({ error: null })}>
            Try again
          </button>
        </div>
      );
    }

    return this.props.children;
  }
}

React Hook for Error Handling

function useSDKOperation<T>(operation: () => Promise<T>) {
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState<PrivacyBoostError | null>(null);
  const [data, setData] = useState<T | null>(null);

  const execute = useCallback(async () => {
    setLoading(true);
    setError(null);

    try {
      const result = await operation();
      setData(result);
      return result;
    } catch (err) {
      const sdkError = err instanceof PrivacyBoostError ? err : PrivacyBoostError.from(err);
      setError(sdkError);
      throw sdkError;
    } finally {
      setLoading(false);
    }
  }, [operation]);

  return { execute, loading, error, data };
}

// Usage
function ShieldButton({ tokenAddress, amount }: { tokenAddress: Hex; amount: bigint }) {
  const { execute, loading, error } = useSDKOperation(() =>
    sdk.vault.shield({ tokenAddress, amount })
  );

  return (
    <>
      <button onClick={execute} disabled={loading}>
        {loading ? 'Processing...' : 'Deposit'}
      </button>
      {error && <p className="error">{error.message}</p>}
    </>
  );
}

Logging Errors

function logError(error: unknown, context: string) {
  if (error instanceof PrivacyBoostError) {
    console.error(`[${context}] SDK Error:`, {
      code: error.code,
      message: error.message,
      cause: error.cause,
    });
  } else {
    console.error(`[${context}] Unknown error:`, error);
  }
}

// Usage
try {
  await sdk.vault.shield(params);
} catch (error) {
  logError(error, 'deposit');
  throw error;
}

Best Practices

1. Always Handle User Rejections Gracefully

if (error.code === 'TRANSACTION_REJECTED') {
  // Don't show error, user intentionally cancelled
  return;
}

2. Provide Actionable Error Messages

const actionableMessages: Record<string, string> = {
  WRONG_NETWORK: 'Click here to switch networks',
  SESSION_EXPIRED: 'Click to reconnect your wallet',
  TRANSACTION_REJECTED: 'Transaction was cancelled',
};

3. Log Errors for Debugging

catch (error) {
  // Log for developers
  console.error('Operation failed:', error);

  // Show user-friendly message
  showToast(getUserMessage(error));
}

4. Use Error Codes, Not Messages

// BAD - Message might change
if (error.message.includes('rejected')) {
  // ...
}

// GOOD - Code is stable
if (error.code === 'TRANSACTION_REJECTED') {
  // ...
}

Next Steps