Exceptions

Handle errors with structured HTTP exception classes.

MiiaJS provides a set of built-in exception classes that produce structured JSON error responses.

HttpException

The base class for all HTTP exceptions:

import { HttpException } from '@miiajs/core'

throw new HttpException(400, 'Invalid input', { field: 'email' })

Response:

{
  "statusCode": 400,
  "error": "Bad Request",
  "message": "Invalid input",
  "details": { "field": "email" }
}

Constructor

new HttpException(statusCode: number, message: string, details?: any)

Built-in exceptions

ClassStatusDefault message
BadRequestException400Bad Request
UnauthorizedException401Unauthorized
ForbiddenException403Forbidden
NotFoundException404Not Found
ConflictException409Conflict
PayloadTooLargeException413Payload Too Large
UnsupportedMediaTypeException415Unsupported Media Type
UnprocessableException422Unprocessable Entity
TooManyRequestsException429Too Many Requests
InternalServerException500Internal Server Error
PayloadTooLargeException is also thrown automatically by the framework when a request body exceeds the configured limit - see Body size limits. TooManyRequestsException is thrown automatically by @miiajs/rate-limit when a client exceeds a rate limit.

Usage

import { NotFoundException, BadRequestException } from '@miiajs/core'

@Get('/:id')
async findOne(ctx: RequestContext) {
  const user = await this.userService.findById(ctx.params.id)
  if (!user) {
    throw new NotFoundException(`User ${ctx.params.id} not found`)
  }
  return user
}

@Post('/')
async create(ctx: RequestContext) {
  const body = await ctx.json<{ email: string }>()
  const exists = await this.userService.findByEmail(body.email)
  if (exists) {
    throw new ConflictException('Email already exists')
  }
  return this.userService.create(body)
}

Error handling

MiiaJS automatically catches all exceptions thrown in route handlers and middleware:

  • HttpException instances are returned with their status code and JSON body
  • All other errors are logged and returned as 500 Internal Server Error
// HttpException -> returned as-is
throw new NotFoundException('Not found')
// -> { statusCode: 404, error: "Not Found", message: "Not found" }

// Unknown error -> 500
throw new Error('something broke')
// -> { statusCode: 500, error: "Internal Server Error", message: "Internal Server Error" }

Custom error handling

Use middleware for custom error handling:

const errorHandler: Middleware = async (ctx, next) => {
  try {
    await next()
  } catch (error) {
    if (error instanceof HttpException) {
      ctx.res.status(error.statusCode).json(error.toJSON())
    } else {
      ctx.res.status(500).json({
        error: 'Unexpected error',
        requestId: ctx.req.headers.get('x-request-id'),
      })
    }
  }
}

app.use(errorHandler)