Skip to content
On this page

Error handling & limitations

Mapping exceptions to gRPC statuses

When a controller method (or a guard) throws, @danet/grpc converts the error into a gRPC status code returned to the client.

Danet's built-in HTTP exceptions are mapped to the closest gRPC status:

Danet exceptionHTTPgRPC status
BadRequestException400INVALID_ARGUMENT
UnauthorizedException401UNAUTHENTICATED
ForbiddenException403PERMISSION_DENIED
NotFoundException404NOT_FOUND
ConflictException409ALREADY_EXISTS
PreconditionFailedException412FAILED_PRECONDITION
TooManyRequestsException429RESOURCE_EXHAUSTED
InternalServerErrorException500INTERNAL
NotImplementedException501UNIMPLEMENTED
ServiceUnavailableException503UNAVAILABLE
GatewayTimeoutException504DEADLINE_EXCEEDED

Any other error maps to UNKNOWN.

ts
@GrpcMethod()
GetUser(@GrpcPayload() request: { id: string }) {
  const user = this.users.find(request.id);
  if (!user) {
    throw new NotFoundException('user not found'); // -> NOT_FOUND on the client
  }
  return user;
}

A denied guard throws ForbiddenException, so the client receives PERMISSION_DENIED.

Exception filters

Exception filters run for gRPC calls just like for HTTP requests. If a filter returns a value, that value is sent back to the client as the RPC reply instead of an error.

ts
@UseFilter(MyGrpcFilter)
@GrpcController(GreeterService)
export class GreeterController { /* ... */ }

Limitations

  • Unary RPCs only for now. Streaming RPCs (server-, client- and bidirectional) are skipped — clients calling them receive UNIMPLEMENTED. Streaming support is planned.
  • Transport-agnostic middleware only — middleware that depends on HTTP ctx.req / ctx.res will not work on gRPC controllers.
  • No DTO validation on the payload. The Protobuf schema is the contract, so the class-validator based validation used by @Body does not apply to @GrpcPayload.