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```