0
# Error Handling
1
2
Standardized error classes for consistent error handling across Expo modules with error codes and platform-specific messaging.
3
4
## Capabilities
5
6
### CodedError Class
7
8
General-purpose error class that provides consistent error handling with error codes for easy categorization and handling.
9
10
```typescript { .api }
11
/**
12
* General error class for all errors in Expo modules
13
* Guarantees a code field for error differentiation
14
*/
15
class CodedError extends Error {
16
/**
17
* Error code for categorizing error types
18
*/
19
code: string;
20
21
/**
22
* Additional error information
23
*/
24
info?: any;
25
26
/**
27
* Create a coded error
28
* @param code - Error code for identification
29
* @param message - Human-readable error message
30
*/
31
constructor(code: string, message: string);
32
}
33
```
34
35
**Usage Examples:**
36
37
```typescript
38
import { CodedError } from "@unimodules/core";
39
40
// Create custom errors
41
function validateInput(data: unknown) {
42
if (!data) {
43
throw new CodedError('INVALID_INPUT', 'Input data is required');
44
}
45
46
if (typeof data !== 'object') {
47
throw new CodedError('INVALID_TYPE', 'Input must be an object');
48
}
49
}
50
51
// Handle coded errors
52
try {
53
await someNativeOperation();
54
} catch (error) {
55
if (error instanceof CodedError) {
56
switch (error.code) {
57
case 'PERMISSION_DENIED':
58
showPermissionDialog();
59
break;
60
case 'NETWORK_ERROR':
61
showRetryButton();
62
break;
63
case 'INVALID_ARGUMENT':
64
showValidationError(error.message);
65
break;
66
default:
67
showGenericError(error.message);
68
}
69
} else {
70
// Handle non-coded errors
71
showGenericError('An unexpected error occurred');
72
}
73
}
74
75
// Add additional error information
76
function createDetailedError(code: string, message: string, details: any) {
77
const error = new CodedError(code, message);
78
error.info = details;
79
return error;
80
}
81
82
const error = createDetailedError(
83
'API_ERROR',
84
'Failed to fetch user data',
85
{
86
endpoint: '/api/users/123',
87
statusCode: 404,
88
timestamp: new Date().toISOString()
89
}
90
);
91
```
92
93
### UnavailabilityError Class
94
95
Specialized error class for features that are unavailable, unsupported, or not implemented on the current platform.
96
97
```typescript { .api }
98
/**
99
* Error for unavailable, unsupported, or unimplemented properties
100
* Automatically includes platform information
101
*/
102
class UnavailabilityError extends CodedError {
103
/**
104
* Create an unavailability error
105
* @param moduleName - Name of the module
106
* @param propertyName - Name of the unavailable property/method
107
*/
108
constructor(moduleName: string, propertyName: string);
109
}
110
```
111
112
**Usage Examples:**
113
114
```typescript
115
import { UnavailabilityError, Platform } from "@unimodules/core";
116
117
// Throw for unsupported features
118
class CameraModule {
119
static async takePictureAsync() {
120
if (Platform.OS === 'web') {
121
throw new UnavailabilityError('Camera', 'takePictureAsync');
122
}
123
// Native implementation
124
return NativeModulesProxy.Camera.takePictureAsync();
125
}
126
127
static async recordVideoAsync() {
128
if (!Platform.select({ ios: true, android: true, default: false })) {
129
throw new UnavailabilityError('Camera', 'recordVideoAsync');
130
}
131
return NativeModulesProxy.Camera.recordVideoAsync();
132
}
133
}
134
135
// Handle unavailability errors
136
try {
137
await CameraModule.takePictureAsync();
138
} catch (error) {
139
if (error instanceof UnavailabilityError) {
140
console.warn(`Feature not available: ${error.message}`);
141
// Show alternative UI or disable feature
142
showFeatureUnavailableMessage();
143
}
144
}
145
146
// Conditional feature checking
147
function createFeatureProxy(moduleName: string) {
148
return new Proxy({}, {
149
get(target, propertyName: string) {
150
const module = NativeModulesProxy[moduleName];
151
if (!module || !(propertyName in module)) {
152
throw new UnavailabilityError(moduleName, propertyName);
153
}
154
return module[propertyName];
155
}
156
});
157
}
158
```
159
160
### Error Code Standards
161
162
Common error codes used throughout the Expo ecosystem:
163
164
```typescript { .api }
165
/**
166
* Standard error codes used across Expo modules
167
*/
168
type StandardErrorCodes =
169
| 'ERR_UNAVAILABLE' // Feature not available on platform
170
| 'ERR_DEPRECATED_API' // API has been deprecated/removed
171
| 'ERR_INVALID_ARGUMENT' // Invalid argument provided
172
| 'ERR_PERMISSION_DENIED' // Permission required but not granted
173
| 'ERR_NETWORK_ERROR' // Network operation failed
174
| 'ERR_FILE_NOT_FOUND' // File system operation failed
175
| 'ERR_OPERATION_CANCELLED' // User cancelled operation
176
| 'ERR_TIMEOUT' // Operation timed out
177
| 'ERR_INITIALIZATION' // Module failed to initialize
178
| 'ERR_PLATFORM_SPECIFIC'; // Platform-specific error
179
```
180
181
**Usage Examples:**
182
183
```typescript
184
import { CodedError } from "@unimodules/core";
185
186
// Use standard error codes
187
function validatePermission(permission: string) {
188
if (!permission) {
189
throw new CodedError('ERR_INVALID_ARGUMENT', 'Permission name is required');
190
}
191
}
192
193
async function requestWithTimeout<T>(operation: Promise<T>, timeout: number): Promise<T> {
194
const timeoutPromise = new Promise<never>((_, reject) => {
195
setTimeout(() => {
196
reject(new CodedError('ERR_TIMEOUT', `Operation timed out after ${timeout}ms`));
197
}, timeout);
198
});
199
200
return Promise.race([operation, timeoutPromise]);
201
}
202
203
// Handle standard error codes
204
function handleStandardError(error: CodedError) {
205
switch (error.code) {
206
case 'ERR_PERMISSION_DENIED':
207
return 'Permission required. Please grant access in settings.';
208
case 'ERR_NETWORK_ERROR':
209
return 'Network error. Please check your connection.';
210
case 'ERR_TIMEOUT':
211
return 'Operation timed out. Please try again.';
212
case 'ERR_UNAVAILABLE':
213
return 'This feature is not available on your device.';
214
default:
215
return `Error: ${error.message}`;
216
}
217
}
218
```
219
220
## Advanced Usage
221
222
### Error Factory Pattern
223
224
```typescript
225
import { CodedError, UnavailabilityError } from "@unimodules/core";
226
227
class ErrorFactory {
228
static createPermissionError(permission: string): CodedError {
229
return new CodedError(
230
'ERR_PERMISSION_DENIED',
231
`${permission} permission is required but not granted`
232
);
233
}
234
235
static createNetworkError(details?: any): CodedError {
236
const error = new CodedError('ERR_NETWORK_ERROR', 'Network request failed');
237
if (details) {
238
error.info = details;
239
}
240
return error;
241
}
242
243
static createValidationError(field: string, value: any): CodedError {
244
const error = new CodedError(
245
'ERR_INVALID_ARGUMENT',
246
`Invalid value for field '${field}'`
247
);
248
error.info = { field, value };
249
return error;
250
}
251
252
static createUnavailableError(module: string, method: string): UnavailabilityError {
253
return new UnavailabilityError(module, method);
254
}
255
}
256
257
// Usage
258
throw ErrorFactory.createPermissionError('CAMERA');
259
throw ErrorFactory.createNetworkError({ statusCode: 500, endpoint: '/api/data' });
260
```
261
262
### Error Recovery Patterns
263
264
```typescript
265
import { CodedError, UnavailabilityError } from "@unimodules/core";
266
267
class ErrorRecovery {
268
static async withRetry<T>(
269
operation: () => Promise<T>,
270
maxRetries: number = 3,
271
delay: number = 1000
272
): Promise<T> {
273
let lastError: Error;
274
275
for (let attempt = 1; attempt <= maxRetries; attempt++) {
276
try {
277
return await operation();
278
} catch (error) {
279
lastError = error;
280
281
// Don't retry certain error types
282
if (error instanceof UnavailabilityError ||
283
(error instanceof CodedError && error.code === 'ERR_PERMISSION_DENIED')) {
284
throw error;
285
}
286
287
if (attempt < maxRetries) {
288
await new Promise(resolve => setTimeout(resolve, delay * attempt));
289
}
290
}
291
}
292
293
throw new CodedError('ERR_MAX_RETRIES_EXCEEDED',
294
`Operation failed after ${maxRetries} attempts: ${lastError.message}`);
295
}
296
297
static async withFallback<T>(
298
primary: () => Promise<T>,
299
fallback: () => Promise<T>
300
): Promise<T> {
301
try {
302
return await primary();
303
} catch (error) {
304
if (error instanceof UnavailabilityError) {
305
console.warn(`Primary method unavailable, using fallback: ${error.message}`);
306
return await fallback();
307
}
308
throw error;
309
}
310
}
311
}
312
313
// Usage
314
const result = await ErrorRecovery.withRetry(async () => {
315
return await fetch('/api/data');
316
});
317
318
const data = await ErrorRecovery.withFallback(
319
() => NativeModulesProxy.Storage.getSecureItem('key'),
320
() => AsyncStorage.getItem('key')
321
);
322
```
323
324
## Types
325
326
```typescript { .api }
327
interface ErrorInfo {
328
[key: string]: any;
329
}
330
331
interface CodedErrorConstructor {
332
new (code: string, message: string): CodedError;
333
prototype: CodedError;
334
}
335
336
interface UnavailabilityErrorConstructor {
337
new (moduleName: string, propertyName: string): UnavailabilityError;
338
prototype: UnavailabilityError;
339
}
340
```