or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

asset-resolution.mdbuiltin-components.mdcomponents.mdcomposition-helpers.mddependency-injection.mderror-handling.mdhydration.mdindex.mdinternal-render-helpers.mdlifecycle.mdreactivity.mdscheduler-timing.mdssr-context.mdvdom-rendering.mdwatch-effects.md

error-handling.mddocs/

0

# Error Handling

1

2

Vue's error handling system provides utilities for graceful error management, including error capture, handling, and reporting mechanisms for building robust applications.

3

4

## Capabilities

5

6

### Error Handling Functions

7

8

Handle errors with proper context and error information.

9

10

```typescript { .api }

11

/**

12

* Handles errors with Vue's error handling pipeline

13

* @param err - Error to handle

14

* @param instance - Component instance where error occurred

15

* @param type - Error type for categorization

16

*/

17

function handleError(

18

err: unknown,

19

instance: ComponentInternalInstance | null,

20

type: ErrorTypes

21

): void;

22

23

/**

24

* Calls a function with error handling

25

* @param fn - Function to call

26

* @param instance - Component instance context

27

* @param type - Error type

28

* @param args - Arguments to pass to function

29

* @returns Function result or undefined on error

30

*/

31

function callWithErrorHandling<T extends any[], R>(

32

fn: (...args: T) => R,

33

instance: ComponentInternalInstance | null,

34

type: ErrorTypes,

35

args?: T

36

): R | undefined;

37

38

/**

39

* Calls async function(s) with error handling

40

* @param fn - Function or array of functions to call

41

* @param instance - Component instance context

42

* @param type - Error type

43

* @param args - Arguments to pass to function(s)

44

* @returns Promise resolving to results

45

*/

46

function callWithAsyncErrorHandling<T extends any[], R>(

47

fn: Function | Function[],

48

instance: ComponentInternalInstance | null,

49

type: ErrorTypes,

50

args?: T

51

): Promise<R[]>;

52

```

53

54

**Usage Examples:**

55

56

```typescript

57

import {

58

defineComponent,

59

handleError,

60

callWithErrorHandling,

61

callWithAsyncErrorHandling,

62

ErrorCodes

63

} from "@vue/runtime-core";

64

65

// Basic error handling

66

const SafeComponent = defineComponent({

67

setup() {

68

const riskyOperation = () => {

69

try {

70

// Some operation that might throw

71

JSON.parse('invalid json');

72

} catch (error) {

73

handleError(error, getCurrentInstance(), ErrorCodes.SETUP_FUNCTION);

74

}

75

};

76

77

// Safe function call with error handling

78

const safeFunctionCall = (userFunction: Function) => {

79

const result = callWithErrorHandling(

80

userFunction,

81

getCurrentInstance(),

82

ErrorCodes.COMPONENT_EVENT_HANDLER

83

);

84

85

console.log('Function result:', result);

86

};

87

88

return {

89

riskyOperation,

90

safeFunctionCall

91

};

92

}

93

});

94

95

// Async error handling

96

const AsyncErrorComponent = defineComponent({

97

setup() {

98

const handleAsyncOperations = async () => {

99

const asyncFunctions = [

100

async () => {

101

await fetch('/api/data1');

102

return 'data1';

103

},

104

async () => {

105

await fetch('/api/data2');

106

return 'data2';

107

},

108

async () => {

109

throw new Error('Intentional error');

110

}

111

];

112

113

const results = await callWithAsyncErrorHandling(

114

asyncFunctions,

115

getCurrentInstance(),

116

ErrorCodes.COMPONENT_EVENT_HANDLER

117

);

118

119

console.log('Async results:', results);

120

};

121

122

return {

123

handleAsyncOperations

124

};

125

}

126

});

127

128

// Error handling in lifecycle hooks

129

const LifecycleErrorComponent = defineComponent({

130

setup() {

131

onMounted(() => {

132

const initializeThirdPartyLib = () => {

133

// Third-party library initialization that might fail

134

window.ThirdPartyLib?.init({

135

apiKey: 'invalid-key'

136

});

137

};

138

139

callWithErrorHandling(

140

initializeThirdPartyLib,

141

getCurrentInstance(),

142

ErrorCodes.COMPONENT_EVENT_HANDLER

143

);

144

});

145

146

return {};

147

}

148

});

149

```

150

151

### Error Codes and Types

152

153

Categorize errors for better handling and debugging.

154

155

```typescript { .api }

156

/**

157

* Enumeration of error codes for different error types

158

*/

159

enum ErrorCodes {

160

SETUP_FUNCTION = 'setup function',

161

RENDER_FUNCTION = 'render function',

162

WATCH_GETTER = 'watcher getter',

163

WATCH_CALLBACK = 'watcher callback',

164

WATCH_CLEANUP = 'watcher cleanup function',

165

NATIVE_EVENT_HANDLER = 'native event handler',

166

COMPONENT_EVENT_HANDLER = 'component event handler',

167

VNODE_HOOK = 'vnode hook',

168

DIRECTIVE_HOOK = 'directive hook',

169

TRANSITION_HOOK = 'transition hook',

170

APP_ERROR_HANDLER = 'app errorHandler',

171

APP_WARN_HANDLER = 'app warnHandler',

172

FUNCTION_REF = 'ref function',

173

ASYNC_COMPONENT_LOADER = 'async component loader',

174

SCHEDULER = 'scheduler flush'

175

}

176

177

type ErrorTypes = ErrorCodes | string;

178

```

179

180

**Usage Examples:**

181

182

```typescript

183

// Custom error handling by type

184

const createErrorHandler = () => {

185

const errorCounts = reactive<Record<string, number>>({});

186

187

const customHandleError = (

188

err: unknown,

189

instance: ComponentInternalInstance | null,

190

type: ErrorTypes

191

) => {

192

// Track error frequency

193

if (typeof type === 'string') {

194

errorCounts[type] = (errorCounts[type] || 0) + 1;

195

}

196

197

// Different handling based on error type

198

switch (type) {

199

case ErrorCodes.RENDER_FUNCTION:

200

console.error('Render error - component may be broken:', err);

201

break;

202

203

case ErrorCodes.ASYNC_COMPONENT_LOADER:

204

console.warn('Async component failed to load:', err);

205

break;

206

207

case ErrorCodes.NATIVE_EVENT_HANDLER:

208

console.error('Native event handler error:', err);

209

break;

210

211

default:

212

console.error(`Error in ${type}:`, err);

213

}

214

215

// Use Vue's default error handling

216

handleError(err, instance, type);

217

};

218

219

return {

220

customHandleError,

221

errorCounts: readonly(errorCounts)

222

};

223

};

224

225

// Error boundary component

226

const ErrorBoundary = defineComponent({

227

setup(_, { slots }) {

228

const hasError = ref(false);

229

const error = ref<Error | null>(null);

230

231

onErrorCaptured((err, instance, info) => {

232

hasError.value = true;

233

error.value = err instanceof Error ? err : new Error(String(err));

234

235

// Log error with context

236

handleError(err, instance, `error boundary: ${info}`);

237

238

// Prevent error from propagating

239

return false;

240

});

241

242

const retry = () => {

243

hasError.value = false;

244

error.value = null;

245

};

246

247

return () => {

248

if (hasError.value) {

249

return h('div', { class: 'error-boundary' }, [

250

h('h3', 'Something went wrong'),

251

h('p', error.value?.message || 'Unknown error'),

252

h('button', { onClick: retry }, 'Retry')

253

]);

254

}

255

256

return slots.default?.();

257

};

258

}

259

});

260

```

261

262

### Development Tools Integration

263

264

Warning and development utilities for debugging.

265

266

```typescript { .api }

267

/**

268

* Development warning utility (only in development mode)

269

* @param msg - Warning message

270

* @param args - Additional arguments to log

271

*/

272

declare const warn: (msg: string, ...args: any[]) => void;

273

274

/**

275

* Assert that a value is a number (development only)

276

* @param val - Value to check

277

* @param type - Context type for error message

278

*/

279

function assertNumber(val: unknown, type: string): void;

280

```

281

282

**Usage Examples:**

283

284

```typescript

285

import { warn, assertNumber } from "@vue/runtime-core";

286

287

const ValidationComponent = defineComponent({

288

props: {

289

count: [Number, String],

290

timeout: Number

291

},

292

293

setup(props) {

294

// Development warnings

295

if (__DEV__) {

296

if (typeof props.count === 'string') {

297

warn('count prop should be a number, received string:', props.count);

298

}

299

300

// Assert number type

301

if (props.timeout !== undefined) {

302

assertNumber(props.timeout, 'timeout prop');

303

}

304

}

305

306

const processCount = () => {

307

const numericCount = typeof props.count === 'string'

308

? parseInt(props.count, 10)

309

: props.count || 0;

310

311

if (__DEV__ && isNaN(numericCount)) {

312

warn('Invalid count value, defaulting to 0');

313

}

314

315

return isNaN(numericCount) ? 0 : numericCount;

316

};

317

318

return {

319

processCount

320

};

321

}

322

});

323

324

// Custom validation with warnings

325

const useValidation = () => {

326

const validateProps = (props: Record<string, any>, schema: Record<string, any>) => {

327

for (const [key, validator] of Object.entries(schema)) {

328

const value = props[key];

329

330

if (validator.required && (value === undefined || value === null)) {

331

if (__DEV__) {

332

warn(`Required prop "${key}" is missing`);

333

}

334

continue;

335

}

336

337

if (value !== undefined && validator.type && typeof value !== validator.type) {

338

if (__DEV__) {

339

warn(`Prop "${key}" expected ${validator.type}, got ${typeof value}`);

340

}

341

}

342

343

if (validator.validator && !validator.validator(value)) {

344

if (__DEV__) {

345

warn(`Prop "${key}" failed custom validation`);

346

}

347

}

348

}

349

};

350

351

return { validateProps };

352

};

353

```

354

355

### Advanced Error Handling Patterns

356

357

```typescript

358

// Global error handler setup

359

const setupGlobalErrorHandling = (app: App) => {

360

app.config.errorHandler = (err, instance, info) => {

361

// Custom global error handling

362

console.error('Global error:', err);

363

console.log('Component:', instance);

364

console.log('Error info:', info);

365

366

// Send to error reporting service

367

sendErrorToService(err, {

368

component: instance?.type?.name || 'Unknown',

369

info,

370

stack: err instanceof Error ? err.stack : undefined

371

});

372

373

// Use Vue's error handling

374

handleError(err, instance, `global handler: ${info}`);

375

};

376

377

app.config.warnHandler = (msg, instance, trace) => {

378

console.warn('Vue warning:', msg);

379

if (instance) {

380

console.log('Component:', instance.type?.name);

381

}

382

console.log('Trace:', trace);

383

};

384

};

385

386

// Error recovery utilities

387

const useErrorRecovery = () => {

388

const retryCount = ref(0);

389

const maxRetries = 3;

390

391

const withRetry = async <T>(

392

operation: () => Promise<T>,

393

errorType: ErrorTypes = ErrorCodes.COMPONENT_EVENT_HANDLER

394

): Promise<T | null> => {

395

try {

396

const result = await callWithAsyncErrorHandling(

397

[operation],

398

getCurrentInstance(),

399

errorType

400

);

401

402

retryCount.value = 0; // Reset on success

403

return result[0];

404

405

} catch (error) {

406

retryCount.value++;

407

408

if (retryCount.value < maxRetries) {

409

console.log(`Retrying operation (${retryCount.value}/${maxRetries})`);

410

return withRetry(operation, errorType);

411

}

412

413

console.error('Max retries exceeded');

414

return null;

415

}

416

};

417

418

return {

419

withRetry,

420

retryCount: readonly(retryCount)

421

};

422

};

423

424

// Circuit breaker pattern

425

class CircuitBreaker {

426

private failures = 0;

427

private lastFailureTime = 0;

428

private state: 'closed' | 'open' | 'half-open' = 'closed';

429

430

constructor(

431

private failureThreshold = 5,

432

private recoveryTimeout = 30000

433

) {}

434

435

async execute<T>(

436

operation: () => Promise<T>,

437

fallback?: () => T

438

): Promise<T> {

439

if (this.state === 'open') {

440

if (Date.now() - this.lastFailureTime > this.recoveryTimeout) {

441

this.state = 'half-open';

442

} else {

443

if (fallback) return fallback();

444

throw new Error('Circuit breaker is open');

445

}

446

}

447

448

try {

449

const result = await callWithAsyncErrorHandling(

450

[operation],

451

null,

452

ErrorCodes.COMPONENT_EVENT_HANDLER

453

);

454

455

// Success - reset circuit breaker

456

if (this.state === 'half-open') {

457

this.state = 'closed';

458

this.failures = 0;

459

}

460

461

return result[0];

462

463

} catch (error) {

464

this.failures++;

465

this.lastFailureTime = Date.now();

466

467

if (this.failures >= this.failureThreshold) {

468

this.state = 'open';

469

}

470

471

if (fallback) return fallback();

472

throw error;

473

}

474

}

475

}

476

```

477

478

## Types

479

480

```typescript { .api }

481

enum ErrorCodes {

482

SETUP_FUNCTION = 'setup function',

483

RENDER_FUNCTION = 'render function',

484

WATCH_GETTER = 'watcher getter',

485

WATCH_CALLBACK = 'watcher callback',

486

WATCH_CLEANUP = 'watcher cleanup function',

487

NATIVE_EVENT_HANDLER = 'native event handler',

488

COMPONENT_EVENT_HANDLER = 'component event handler',

489

VNODE_HOOK = 'vnode hook',

490

DIRECTIVE_HOOK = 'directive hook',

491

TRANSITION_HOOK = 'transition hook',

492

APP_ERROR_HANDLER = 'app errorHandler',

493

APP_WARN_HANDLER = 'app warnHandler',

494

FUNCTION_REF = 'ref function',

495

ASYNC_COMPONENT_LOADER = 'async component loader',

496

SCHEDULER = 'scheduler flush'

497

}

498

499

type ErrorTypes = ErrorCodes | string;

500

501

interface ErrorHandler {

502

(err: unknown, instance: ComponentInternalInstance | null, info: string): void;

503

}

504

505

interface WarnHandler {

506

(msg: string, instance: ComponentInternalInstance | null, trace: string): void;

507

}

508

```

509

510

## Best Practices

511

512

### Error Handling Strategy

513

514

1. **Graceful Degradation**: Always provide fallbacks for failed operations

515

2. **Error Boundaries**: Use `onErrorCaptured` to contain errors within components

516

3. **Contextual Logging**: Include component and operation context in error reports

517

4. **User-Friendly Messages**: Don't expose technical errors directly to users

518

519

### Development vs Production

520

521

```typescript

522

// Development-only error handling

523

if (__DEV__) {

524

warn('This is a development warning');

525

assertNumber(value, 'prop name');

526

}

527

528

// Production error handling

529

const handleProductionError = (error: unknown) => {

530

// Log to service, show user-friendly message

531

console.error('An error occurred');

532

// Don't expose internal details

533

};

534

```

535

536

### Error Recovery Patterns

537

538

1. **Retry Logic**: Implement retry mechanisms for transient failures

539

2. **Circuit Breakers**: Prevent cascading failures in distributed systems

540

3. **Fallback Content**: Always have backup content for failed async operations

541

4. **Error Boundaries**: Isolate errors to prevent full application crashes