What counts as an error
Define what a failure means for each entrypoint kind — HTTP status codes, GraphQL error codes, message handlers, exit codes — and drive the error tag and the Errors filter from your own definition.
Not everyone agrees on what an "error" is. A 404 is a bug for one team and an ordinary answer for another; a 401 is routine on a public API and an incident on an internal one. So the profiler ships no universal definition — each entrypoint kind carries its own, and you can redefine it.
That definition drives everything failure-related: the error tag, its pill in the panels and the list, and the Errors checkbox on the list page.
The defaults
| Kind | A profile is an error when… | Configured on |
|---|---|---|
http | The response status is ≥ 500 — or an exception was captured and no status was recorded | ProfilerModule.forRoot({ error }) |
graphql | An error in errors carries extensions.code: INTERNAL_SERVER_ERROR, or carries no code at all | GraphQLCollectorModule.forRoot({ error }) |
rabbitmq | The handler threw | RabbitMqCollectorModule.forRoot({ error }) |
command | The command exited non-zero | Not configurable — see below |
Outgoing calls your app makes are judged separately, per entry: an outgoing call is failed when it threw or answered ≥ 500 (HttpCollectorModule.forRoot({ error })).
4xx are not errors by default. 401, 403, 404 and friends mean your application answered correctly. If yours treats them as failures, one line brings them back: ProfilerModule.forRoot({ error: { httpStatus: 400 } }).
Configuring it
The option is the same shape everywhere. Its layers are resolved in order, and the first that applies is decisive:
classify— return a boolean to settle it,undefinedto defer to the layers below.httpStatus— when the profile carries a status, that status decides on its own.exceptions— the fallback for kinds carrying no status.
Layer 2 being decisive is what keeps the defaults coherent: a NotFoundException produces both a captured exception and a 404, so if the exceptions were also consulted they would contradict the status and re-flag the very 404 you excluded. For a kind that answers with a status, the status is the verdict.
// Count 4xx as errors too.
ProfilerModule.forRoot({ error: { httpStatus: 400 } });
// Anything but a 404 — that one is expected here.
ProfilerModule.forRoot({ error: { httpStatus: (code) => code >= 400 && code !== 404 } });
// A teapot is an incident; everything else keeps the default.
ProfilerModule.forRoot({
error: {
classify: ({ statusCode }) => (statusCode === 418 ? true : undefined),
},
});GraphQL
A GraphQL response is 200 even when the operation failed — the failure lives in the errors array. Statuses therefore say nothing here, and extensions.code takes their role: it is GraphQL's equivalent of a status code.
By default only INTERNAL_SERVER_ERROR counts, plus any error carrying no code (an unmapped throw is a genuine failure). BAD_REQUEST — what the Nest Apollo driver emits when validation rejects a mutation — along with BAD_USER_INPUT, UNAUTHENTICATED, FORBIDDEN and NOT_FOUND, is the schema answering correctly: GraphQL's 4xx.
The code is shown as a badge next to the error on the Exceptions tab, and it is what the Exception filter lists — GraphQL names every error GraphQLError, so the code is the only thing that tells them apart.
// Here, a failed login is an incident worth surfacing.
GraphQLCollectorModule.forRoot({
error: { codes: ['INTERNAL_SERVER_ERROR', 'UNAUTHENTICATED'] },
});RabbitMQ
A consumed message has no status code, so the verdict rests on whether the handler threw.
// A handler that throws to trigger a retry is not an incident; a timeout is.
RabbitMqCollectorModule.forRoot({ error: { exceptions: ['TimeoutError'] } });
// Or decide from the message itself.
RabbitMqCollectorModule.forRoot({
error: { classify: ({ profile }) => profile.entrypoint.data.redelivered === true },
});Outgoing HTTP calls
The calls your app makes are judged one by one, independently of whether the incoming request that made them is itself considered failed.
// Any non-2xx from our upstreams is a problem worth flagging.
HttpCollectorModule.forRoot({ error: { httpStatus: 400 } });Commands
command is the one kind with nothing to configure: a command either exited zero or it did not, and nobody disagrees about which is a failure. Its list also hides the Errors checkbox, since the Status: Success/Failed filter already asks exactly that question under a clearer name.
Errors vs Exception: two different questions
The list page offers both, and they are complementary:
- The Errors checkbox asks "what failed?" — your configured verdict. With the defaults, a
404is not kept even though itsNotFoundExceptionwas captured. - The Exception select asks "show me the
NotFoundExceptions" — the failure type actually captured, whether or not it counts as an error. Its options are not a fixed list: they are the values present in your store, so each list offers only what it has really seen. For GraphQL it offers error codes rather than class names, since every GraphQL error is aGraphQLError.
Severity
The error tag is danger by default. Like every other tag, its severity is configurable — and lowering it re-colours the pill and the collector tab consistently:
ProfilerModule.forRoot({ error: { severity: 'warning' } });Reference
Prop
Type
Prop
Type
Prop
Type
Custom entrypoint kinds
A kind you contribute yourself declares its own verdict on its ProfilerEntrypointType. Build the predicate with resolveProfileErrorClassifier so your users get the same layered option shape for free:
import { resolveProfileErrorClassifier, resolveErrorSeverity } from '@eleven-labs/nest-profiler';
import type { ProfilerEntrypointType, ProfilerErrorOptions } from '@eleven-labs/nest-profiler';
export function buildCronEntrypointType(error?: ProfilerErrorOptions): ProfilerEntrypointType {
return {
...CRON_ENTRYPOINT_TYPE_DEF,
// A cron job carries no status: the job throwing is the signal.
isError: resolveProfileErrorClassifier(error, { httpStatus: false }),
errorSeverity: resolveErrorSeverity(error),
// Hide a universal filter that is redundant on this kind's list.
hiddenFilters: [],
};
}Performance tags (N+1, slow, error…)
Detect N+1 queries, slow queries, failed HTTP calls, chatty endpoints, large payloads and silent zero-row writes with the core rule-based tagging engine, and filter profiles by tag.
Extending the UI with JavaScript
Ship browser behaviour as compiled same-origin bundles and reuse the window.NestProfiler runtime from your own collector package.