@talosjs/exception package gives the framework one consistent way to fail. Instead of throwing bare Error objects, you throw an Exception, a subclass of the native Error that also carries an HTTP status code, an optional grouping key, immutable contextual data, the timestamp it was created, and, when you wrap a native error, the original error. Specialized subclasses like NotFoundException preset the status code so the most common HTTP failures read clearly at the throw site and map straight onto an error response.
What an Exception carries
Every exception carries astatus code, defaulting to 500. Those codes come from @talosjs/http-status, so an exception maps directly onto the response it should produce. You can attach a plain object of contextual data (the failing field, an entity id) at the throw site; it is frozen with Object.freeze, so the context that explains the failure cannot be mutated as the error propagates. Each exception also records its creation date, giving logs and error responses an accurate moment of failure without extra bookkeeping.
A couple of features help when you need to inspect a failure. stackToJson() parses the raw stack string into a structured ExceptionStackFrameType[] (function name, file, line, column) that you can log or expose in a debug-only response field. And when a third-party call throws a plain Error, you can pass it straight into the constructor: its message is reused and the original is preserved on native, so the underlying stack survives. The specialized subclasses, BadRequestException, NotFoundException, UnauthorizedException, and MethodNotAllowedException, each preset the right status code so intent is obvious where you throw.
How it works
Exception extends Error implements IException. The constructor takes the message (or an Error to wrap) and an options object. It reads status, key, and data, freezes data, sets name to the concrete class name, and, if the message was an Error, stores it on native. The date is captured the moment the instance is created.
The base constructor signature is:
stackToJson() matches ExceptionStackFrameType:
The base Exception
Throw anException directly when no specialized type fits. With only a message it defaults to status 500 and empty data:
data object is frozen, so reading it downstream is safe. Attempting to mutate it has no effect.
Specialized exceptions
The specialized exceptions extendException and preset the status code from @talosjs/http-status. Their constructor is positional: a message, a required key string, and an optional data object (defaults to {}).
Throwing from a service or controller
Throw exceptions where the failure is detected, in a service or a controller, and let the calling layer turn them into a response. Because each exception carries its ownstatus and data, the handler does not need to know how to classify the failure:
status and data you attached at the throw site flow straight into the error response. See Response for how context.response.exception(...) and the related helpers serialize this, and Controller for where this handling belongs.
Wrapping a native error
When a third-party call or a built-in throws a plainError, wrap it instead of swallowing it. Pass the caught error as the message: the constructor reuses its message and keeps the original on native, so the underlying context is never lost:
exception.message and exception.data describe the application-level failure, while exception.native holds the original error and its stack.
Inspecting the stack as JSON
stackToJson() turns the raw stack string into structured frames you can log or filter, rather than a single opaque string:
Guidance for throwing well
Throw anException (or a specialized subclass) rather than a bare Error, so every failure carries a status code and structured data a handler can act on uniformly. Reach for NotFoundException, BadRequestException, UnauthorizedException, or MethodNotAllowedException when one of them fits; their preset status codes make the intent obvious at the throw site.
Put ids, field names, and constraints in data, where they stay machine-readable, and keep the message human-readable. A stable key then lets you classify, route, and translate errors without parsing the message string. Send exceptions to the Logger and use stackToJson() and data for searchable records instead of concatenated strings.
Two things to be careful with. Expose stackToJson() only in non-production responses; in production, surface message, status, and safe data and nothing more. And when you catch a native error, wrap it so its message and stack survive on native while you add application context, rather than discarding it.