| name | vf-error-handling |
| description | Use when creating new errors, migrating error classes to registry, catching/handling errors, or working with the VeryfrontError system |
Veryfront Error Handling
Overview
Veryfront uses a centralized error registry with slug-based identification. All errors extend VeryfrontError and are created via defineError().
Core principle: Never throw raw Error. Use the registry. Never identify errors by class name. Use slugs.
Error Registry Pattern
Defining New Errors
import { defineError } from "./types.ts";
export const MY_NEW_ERROR = defineError({
slug: "my-new-error",
category: "RUNTIME",
status: 500,
title: "Something went wrong",
suggestion: "Try doing X instead",
});
Throwing Errors
import { MY_NEW_ERROR } from "#veryfront/errors";
throw MY_NEW_ERROR.create({
detail: "Specific description of what happened",
context: { key: "value", relevantData: data },
cause: originalError,
});
Catching Errors
import { VeryfrontError } from "#veryfront/errors";
try {
riskyOperation();
} catch (error) {
if (error instanceof VeryfrontError && error.slug === "my-new-error") {
console.log(error.context.relevantData);
}
throw error;
}
Migrating Class-Based Errors to Registry
When replacing class FooError extends Error:
Step 1: Define in Registry
export const FOO_ERROR = defineError({
slug: "foo-error",
category: "RUNTIME",
status: 500,
title: "Foo operation failed",
suggestion: "Check the foo configuration",
});
Step 2: Update Usage Sites
throw new FooError("something failed", { details: data });
throw FOO_ERROR.create({
detail: "something failed",
context: { details: data },
});
Step 3: Update Error Checks
if (error instanceof FooError) { ... }
if (error instanceof VeryfrontError && error.slug === "foo-error") { ... }
Step 4: Update Export Chains
Follow the re-export chain and update each level:
src/module/types.ts — remove class, add registry import if needed
src/module/index.ts — change export
- Parent
index.ts files up the chain
src/module/index.test.ts — change typeof X === "function" to typeof X === "object"
Step 5: Remove Old Class
Delete the old error class file entirely. No backwards-compatibility shims.
VeryfrontError Fields
| Field | Type | Purpose |
|---|
slug | string | Unique identifier (kebab-case) |
category | ErrorCategory | Error domain |
status | number | HTTP status code |
title | string | Human-readable title |
suggestion | string | Actionable fix |
detail | string | Specific instance description |
context | Record<string, unknown> | Structured metadata |
cause | Error | Original error (chain) |
instance | string | Request/instance identifier |
RFC 9457 Support
const problemDetails = error.toRFC9457();
Intentionally Local Errors
Five errors remain as local classes by design (not in registry):
SemaphoreTimeoutError
TransformTreeTimeoutError
NotSupportedError
TimeoutError
StreamTimeoutError
Do not migrate these to the registry.
Common Mistakes
| Mistake | Fix |
|---|
throw new Error("msg") | Use registry: MY_ERROR.create({ detail: "msg" }) |
instanceof FooError | instanceof VeryfrontError && error.slug === "foo-error" |
Storing data in error.message | Use error.detail and error.context |
| Forgetting to update index.test.ts | Change function→object type check |
| Creating error class in module | Define in src/errors/error-registry.ts |