DocumentationfrontendError Handling

Error Handling

CredDAO uses React Error Boundaries for graceful error handling.

Basic Usage

ErrorBoundary Component

import { ErrorBoundary } from '@/components/ErrorBoundary'
 
<ErrorBoundary>
  <RiskyComponent />
</ErrorBoundary>

When an error occurs, displays a fallback UI with:

  • Error message
  • “Try Again” button to reset

Custom Fallback

<ErrorBoundary 
  fallback={<CustomErrorUI />}
>
  <Component />
</ErrorBoundary>

Specialized Boundaries

WalletErrorBoundary

For wallet-related errors:

import { WalletErrorBoundary } from '@/components/ErrorBoundary'
 
<WalletErrorBoundary>
  <WalletDependentComponent />
</WalletErrorBoundary>

Shows: “Wallet connection error. Please refresh and reconnect.”

ProposalErrorBoundary

For proposal rendering:

import { ProposalErrorBoundary } from '@/components/ErrorBoundary'
 
<ProposalErrorBoundary>
  <ProposalCard proposal={proposal} />
</ProposalErrorBoundary>

Shows: “Failed to load proposal. It may have been removed.”

VoteErrorBoundary

For voting components:

import { VoteErrorBoundary } from '@/components/ErrorBoundary'
 
<VoteErrorBoundary>
  <VoteButton />
</VoteErrorBoundary>

DataErrorBoundary

For generic data loading:

import { DataErrorBoundary } from '@/components/ErrorBoundary'
 
<DataErrorBoundary message="Failed to load analytics data">
  <AnalyticsWidget />
</DataErrorBoundary>

Architecture

App-Level Boundary

Wrap the entire app in layout:

// app/layout.tsx
<ErrorBoundary>
  <WalletProvider>
    <ToastProvider>
      {children}
    </ToastProvider>
  </WalletProvider>
</ErrorBoundary>

Component-Level Boundaries

Wrap specific features:

<ErrorBoundary>
  <Dashboard>
    <WalletErrorBoundary>
      <ReputationCard />
    </WalletErrorBoundary>
    
    <DataErrorBoundary message="Failed to load proposals">
      <ActiveProposals />
    </DataErrorBoundary>
  </Dashboard>
</ErrorBoundary>

Error Recovery

Automatic Reset

The “Try Again” button resets error state:

// Internal implementation
<button onClick={() => this.setState({ hasError: false, error: null })}>
  Try Again
</button>

Manual Recovery

Use key to force remount:

const [retryKey, setRetryKey] = useState(0)
 
<ErrorBoundary key={retryKey}>
  <Component />
</ErrorBoundary>
 
<button onClick={() => setRetryKey(k => k + 1)}>
  Retry
</button>

Error Logging

Errors are logged to console:

componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
  console.error('ErrorBoundary caught:', error, errorInfo)
}

For production, integrate with error tracking:

componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
  // Send to Sentry, LogRocket, etc.
  captureException(error, { extra: errorInfo })
}

Best Practices

1. Granular Boundaries

Don’t catch everything at once:

// Bad - one error breaks everything
<ErrorBoundary>
  <Header />
  <Sidebar />
  <MainContent />
</ErrorBoundary>
 
// Good - isolate failures
<>
  <ErrorBoundary><Header /></ErrorBoundary>
  <ErrorBoundary><Sidebar /></ErrorBoundary>
  <ErrorBoundary><MainContent /></ErrorBoundary>
</>

2. Contextual Messages

Provide specific error context:

<DataErrorBoundary message="Failed to load voting history">
  <VotingHistory />
</DataErrorBoundary>

3. Recovery Actions

Offer ways to recover:

// In fallback
<div>
  <p>{error.message}</p>
  <button onClick={retry}>Retry</button>
  <button onClick={goBack}>Go Back</button>
  <button onClick={reload}>Reload Page</button>
</div>

4. Graceful Degradation

Show partial content when possible:

// Instead of complete failure
{error ? (
  <FallbackComponent />
) : (
  <FullComponent data={data} />
)}
 
// Show partial
{error ? (
  <PartialComponent fallbackData={cachedData} />
) : (
  <FullComponent data={data} />
)}

Error States by Feature

FeatureBoundaryFallback Message
WalletWalletErrorBoundary”Please reconnect wallet”
ProposalProposalErrorBoundary”Proposal may be removed”
VoteVoteErrorBoundary”Vote failed to load”
AnalyticsDataErrorBoundary”Failed to load data”
AdminDataErrorBoundary”Failed to load admin data”