Skip to content

Error Handling

Velox TS provides a hierarchy of error classes (NotFoundError, ValidationError, UnauthorizedError, and more) that automatically map to the correct HTTP status codes and return structured JSON.

import { NotFoundError, ValidationError, fail } from '@veloxts/core';
getUser: procedure()
.input(z.object({ id: z.string() }))
.query(async ({ input, ctx }) => {
const user = await ctx.db.user.findUnique({ where: { id: input.id } });
if (!user) {
throw new NotFoundError('User not found');
}
return user;
}),
ErrorStatusUse Case
ValidationError400Invalid input
NotFoundError404Resource not found
UnauthorizedError401Not authenticated
ForbiddenError403Not authorized
ConflictError409Resource conflict
import { VeloxError } from '@veloxts/core';
class PaymentError extends VeloxError {
constructor(message: string) {
super(message, 'PAYMENT_FAILED', 402);
}
}

Built-in errors like NotFoundError and ConflictError cover standard HTTP situations. When your business logic needs structured error data that clients can act on — “not enough stock, 3 available” — use DomainError:

import { DomainError } from '@veloxts/core';
export class InsufficientStock extends DomainError<{
sku: string;
requested: number;
available: number;
}> {
readonly code = 'INSUFFICIENT_STOCK';
readonly status = 422;
readonly message = 'Not enough inventory';
}

Throw it like any error:

throw new InsufficientStock({
sku: 'ABC-123',
requested: 10,
available: 3,
});

The framework serializes it as:

{
"error": "InsufficientStock",
"message": "Not enough inventory",
"statusCode": 422,
"code": "INSUFFICIENT_STOCK",
"data": { "sku": "ABC-123", "requested": 10, "available": 3 }
}

Use isDomainError() to detect domain errors across packages:

import { isDomainError } from '@veloxts/core';
if (isDomainError(error)) {
console.log(error.code, error.data);
}

Declare domain errors on the procedure builder with .throws() to enable client-side type narrowing. See Business Logic for details.

{
"error": {
"message": "User not found",
"code": "NOT_FOUND"
}
}

Velox TS uses structured error codes (E1xxx-E9xxx) with fix suggestions:

VeloxError[E1001]: Procedure "getUser" missing required input schema
Fix: Add .input() to your procedure definition