home / skills / onekeyhq / app-monorepo / 1k-error-handling

1k-error-handling skill

/.claude/skills/1k-error-handling

This skill helps you implement robust error handling patterns across async calls, UI states, and user notifications for reliable applications.

npx playbooks add skill onekeyhq/app-monorepo --skill 1k-error-handling

Review the files below or copy the command above to add this skill to your agents.

Files (2)
SKILL.md
3.6 KB
---
name: 1k-error-handling
description: Error handling patterns — try/catch, async errors, error boundaries, useAsyncCall, and toast messages.
allowed-tools: Read, Grep, Glob
---

# Error Handling

Best practices for error handling in OneKey codebase.

## Core Principles

- Use try/catch blocks for async operations that might fail
- Provide appropriate error messages and fallbacks
- Use `useAsyncCall` hook for operations needing loading/error states
- **Never swallow errors silently**

## Quick Reference

### Basic Try/Catch
```typescript
async function fetchData() {
  try {
    const result = await apiCall();
    return result;
  } catch (error) {
    console.error('Failed to fetch data:', error);
    throw error; // Re-throw if caller needs to handle
  }
}
```

### With Fallback Value
```typescript
async function fetchDataWithFallback() {
  try {
    const result = await apiCall();
    return result;
  } catch (error) {
    console.error('Failed to fetch, using fallback:', error);
    return defaultValue; // Return fallback instead of throwing
  }
}
```

### Using useAsyncCall Hook
```typescript
import { useAsyncCall } from '@onekeyhq/kit/src/hooks/useAsyncCall';

function MyComponent() {
  const { run, isLoading, error, result } = useAsyncCall(
    async () => {
      return await fetchData();
    },
    {
      onError: (e) => {
        Toast.error({ title: 'Failed to load data' });
      },
    }
  );

  if (error) {
    return <ErrorView error={error} onRetry={run} />;
  }

  return <DataView data={result} loading={isLoading} />;
}
```

### User-Facing Errors
```typescript
async function submitForm(data: FormData) {
  try {
    await api.submit(data);
    Toast.success({ title: 'Submitted successfully' });
  } catch (error) {
    // Show user-friendly message
    Toast.error({
      title: 'Submission failed',
      message: getUserFriendlyMessage(error),
    });
    // Log detailed error for debugging
    console.error('Form submission error:', error);
  }
}
```

## Anti-Patterns

### Silent Error Swallowing
```typescript
// ❌ BAD: Error silently ignored
async function badExample() {
  try {
    await riskyOperation();
  } catch (error) {
    // Nothing here - error lost forever
  }
}

// ✅ GOOD: At minimum, log the error
async function goodExample() {
  try {
    await riskyOperation();
  } catch (error) {
    console.error('Operation failed:', error);
    // Handle appropriately
  }
}
```

### Missing Error State in UI
```typescript
// ❌ BAD: No error state
function BadComponent() {
  const { data } = useQuery();
  return <View>{data}</View>; // What if data fetch fails?
}

// ✅ GOOD: Handle all states
function GoodComponent() {
  const { data, isLoading, error } = useQuery();

  if (isLoading) return <Loading />;
  if (error) return <Error error={error} />;
  return <View>{data}</View>;
}
```

## Detailed Guide

For comprehensive error handling patterns and examples, see [error-handling.md](references/rules/error-handling.md).

Topics covered:
- Core principles
- Error handling patterns (try/catch, fallbacks, hooks)
- Error boundaries for React
- Error types (network, validation, user-facing)
- Anti-patterns to avoid
- Error handling checklist

## Checklist

- [ ] All async operations wrapped in try/catch
- [ ] Errors logged for debugging
- [ ] User-friendly messages shown to users
- [ ] Loading and error states handled in UI
- [ ] No silent error swallowing
- [ ] Specific error types caught when appropriate

## Related Skills

- `/1k-coding-patterns` - General coding patterns and promise handling
- `/1k-sentry-analysis` - Sentry error analysis and fixes

Overview

This skill describes pragmatic error handling patterns used across a secure, cross-platform crypto wallet codebase. It covers try/catch usage, async error management, React error boundaries, a useAsyncCall hook pattern, and user-facing toast messages. The guidance focuses on reliable user experience, clear logging for debugging, and avoiding silent failures.

How this skill works

The skill inspects common async flows and UI state handling, showing where to wrap operations in try/catch, when to return fallbacks, and how to propagate errors. It demonstrates integrating a useAsyncCall hook to manage loading, result, and error states, and how to display toast notifications for success or user-friendly failures. It also highlights anti-patterns like silent swallowing and missing error UI states.

When to use it

  • Any async operation that can fail (network calls, wallet operations, signing).
  • Components that fetch data and must show loading, success, or error states.
  • Forms and submit flows where users need clear success/failure feedback.
  • Critical flows requiring error logging and re-throwing for upstream handlers.
  • UI boundaries where React error boundaries can prevent full app crashes.

Best practices

  • Always wrap async work in try/catch; log the error and decide to re-throw or provide a fallback.
  • Use useAsyncCall (or equivalent) for components to centralize loading, result, and error handling.
  • Show user-friendly toast messages for errors and successes; log detailed errors for debugging.
  • Never silently swallow errors—at minimum console.error or forward to a monitoring tool.
  • Handle specific error types when possible (network, validation, auth) to provide precise messages.

Example use cases

  • Fetching account balances with a fallback value when remote service is unavailable.
  • Form submission that shows success toast, or error toast with a friendly message and logs details.
  • Component using useAsyncCall to load transaction history and rendering an ErrorView with retry.
  • Wrapping wallet signing calls with try/catch to surface key errors and avoid silent failures.
  • Adding React error boundaries around critical UI sections to capture rendering exceptions.

FAQ

Should I always re-throw errors after catching them?

Re-throw when the caller must know about the failure; otherwise handle locally and provide a meaningful fallback or user message.

When is a fallback acceptable instead of throwing?

Use fallbacks for non-critical data where degraded functionality is acceptable and keeps the UI usable.