Skip to main content

Hono

Map @gentleduck/error instances to JSON responses with Hono's app.onError hook, portable across every Hono runtime target.

Overview

Hono centralizes error handling in one app.onError hook, called for anything thrown inside a route or middleware. Because Hono targets multiple runtimes (Node, Bun, Deno, Cloudflare Workers, Vercel Edge), the handler builds a Response directly rather than relying on a Node-specific res object.

Full runnable example: examples/hono.

Error hook

import { Hono } from 'hono'
import { AppError } from './errors'

const app = new Hono()

app.onError((err, c) => {
  if (err instanceof AppError) {
    return c.json(err.toJSON(), err.status as any)
  }
  console.error(err)
  return c.json({ ok: false, error: { code: 'INTERNAL', status: 500 } }, 500)
})

Throwing from a route

import { throwAppError } from './errors'

app.get('/widgets/:id', async (c) => {
  const widget = await db.widgets.findById(c.req.param('id'))
  if (!widget) throwAppError('NOT_FOUND', { resource: 'widget', id: c.req.param('id') })
  return c.json(widget)
})

onError catches a throw from inside an async route handler the same way it catches a synchronous one. No wrapping needed.