a reactive (signals based) hypermedia web framework (wip) stormlightlabs.github.io/volt/
hypermedia frontend signals
1# Error Handling 2 3⚠️ Named error classes and enhanced error handling are unreleased as of writing. This documentation describes features planned for v0.6.0. 4 5VoltX categorizes all errors by source and severity, wrapping them in named error classes with rich debugging context. This system enables precise error identification, flexible handling strategies, and seamless integration with logging services. 6 7## Error Types 8 9Each error source maps to a specific error class: 10 11| Identifier | Source | Cause | 12| ---------------- | ----------- | ----------------------------------------------------------------------------------------------------------------------------------- | 13| `EvaluatorError` | `evaluator` | Expression evaluation fails in directives (`data-volt-text`, `data-volt-if`, etc.) or computed values | 14| `BindingError` | `binding` | Directive setup or execution fails (`data-volt-model` with missing signal, invalid `data-volt-for` syntax, missing parent elements) | 15| `EffectError` | `effect` | Effect callbacks, computed signals, or async effects fail during execution or cleanup | 16| `HttpError` | `http` | HTTP directives encounter network errors, invalid swap strategies, missing target elements, or parsing failures | 17| `PluginError` | `plugin` | Custom plugin handlers fail during initialization or execution | 18| `LifecycleError` | `lifecycle` | Lifecycle hooks (`beforeMount`, `afterMount`, `onMount`, etc.) fail during execution | 19| `ChargeError` | `charge` | `charge()` encounters invalid `data-volt-state` JSON, malformed configuration, or initialization errors | 20| `UserError` | `user` | User code explicitly reports errors via `report()` | 21 22All error classes extend `VoltError` and set their `name` property accordingly (e.g., `error.name === "HttpError"`). 23 24## Severity Levels 25 26Errors have three severity levels that control console output and execution flow: 27 28**warn** — Non-critical issues logged via `console.warn`. Execution continues. Use for deprecations, missing optional features, or recoverable configuration issues. 29 30**error** (default) — Recoverable errors logged via `console.error`. Execution continues but the specific operation fails. Most runtime errors use this level. 31 32**fatal** — Unrecoverable errors logged via `console.error` and then thrown, halting execution. Reserve for critical initialization failures or corrupted state. 33 34## Error Context 35 36Every VoltX error includes contextual metadata for debugging: 37 38```ts 39interface VoltError { 40 name: string; // Error class name 41 source: ErrorSource; // Error category 42 level: ErrorLevel; // Severity level 43 directive?: string; // Failed directive (e.g., "data-volt-text") 44 expression?: string; // Failed expression 45 element?: HTMLElement; // DOM element where error occurred 46 cause: Error; // Original wrapped error 47 timestamp: number; // Unix timestamp (ms) 48 context: ErrorContext; // Full context including custom properties 49 50 // HTTP errors only 51 httpMethod?: string; 52 httpUrl?: string; 53 httpStatus?: number; 54 55 // Plugin errors only 56 pluginName?: string; 57 58 // Lifecycle errors only 59 hookName?: string; 60} 61``` 62 63## Handling Errors 64 65### Registration 66 67Register global error handlers with `onError()`. Handlers execute in registration order and receive all errors: 68 69```ts 70import { onError } from "voltx.js"; 71 72const cleanup = onError((error) => { 73 analytics.track("error", error.toJSON()); 74 75 if (error instanceof HttpError) { 76 showToast(`Request failed: ${error.cause.message}`); 77 } 78}); 79 80// Cleanup when done 81cleanup(); 82``` 83 84### Propagation Control 85 86Call `error.stopPropagation()` to prevent subsequent handlers from running: 87 88```ts 89onError((error) => { 90 if (error.source === "http") { 91 handleHttpError(error); 92 error.stopPropagation(); 93 } 94}); 95 96// This handler won't run for HTTP errors 97onError((error) => logToConsole(error)); 98``` 99 100### Cleanup 101 102Remove handlers individually via their cleanup function or clear all handlers with `clearErrorHandlers()`. 103 104## Console Fallback 105 106When no handlers are registered, errors log to console based on severity (`console.warn` for warn, `console.error` for error/fatal) with formatted context: 107 108```text 109[ERROR] [evaluator] Cannot read property 'foo' of undefined | Directive: data-volt-text | Expression: user.foo | Element: <div#app> 110Caused by: TypeError: Cannot read property 'foo' of undefined 111Element: <div id="app">...</div> 112``` 113 114Fatal errors throw after logging. 115 116## Reporting Errors 117 118Report errors from user code using `report(error, context)`: 119 120```ts 121import { report } from "voltx.js"; 122 123try { 124 processForm(formElement); 125} catch (error) { 126 report(error as Error, { 127 source: "user", 128 level: "warn", 129 element: formElement as HTMLElement, 130 formId: formElement.id, 131 }); 132} 133``` 134 135The `context` object accepts any custom properties beyond the standard fields. 136 137## Serialization 138 139All VoltX errors implement `toJSON()` for serialization to logging services or error tracking systems. 140 141### Schema 142 143```ts 144interface SerializedVoltError { 145 /** Error class name (e.g., "EvaluatorError", "HttpError") */ 146 name: string; 147 /** Full formatted error message with context */ 148 message: string; 149 /** Error source category */ 150 source: 151 | "evaluator" 152 | "binding" 153 | "effect" 154 | "http" 155 | "plugin" 156 | "lifecycle" 157 | "charge" 158 | "user"; 159 160 /** Severity level */ 161 level: "warn" | "error" | "fatal"; 162 /** Directive name (e.g., "data-volt-text") */ 163 directive?: string; 164 /** Expression that failed */ 165 expression?: string; 166 /** Unix timestamp in milliseconds */ 167 timestamp: number; 168 /** Full error context including custom properties */ 169 context: { 170 source: string; 171 level?: string; 172 element?: HTMLElement; 173 directive?: string; 174 expression?: string; 175 pluginName?: string; 176 httpMethod?: string; 177 httpUrl?: string; 178 httpStatus?: number; 179 hookName?: string; 180 [key: string]: unknown; 181 }; 182 /** Original error that was wrapped */ 183 cause: { name: string; message: string; stack?: string; }; 184 /** VoltX error stack trace */ 185 stack?: string; 186} 187``` 188 189### Usage 190 191```ts 192import { onError } from "voltx.js"; 193 194onError((error) => { 195 fetch("/api/errors", { 196 method: "POST", 197 headers: { "Content-Type": "application/json" }, 198 body: JSON.stringify(error.toJSON()), 199 }); 200}); 201```