Overview
Handling errors cleanly and returning appropriate HTTP responses are crucial parts of building robust web applications. This guide covers how to manage application exceptions using HTTPException, catch unhandled errors with .onError(), customize missing page responses with .notFound(), and inspect errors inside your handlers and middleware using Context.
Using HTTPException for HTTP Status Codes
Basics of HTTPException
When fatal errors occur—such as authentication failures, bad inputs, or unauthorized access—you can throw an HTTPException. This class extends the native JavaScript Error class and accepts an HTTP status code along with optional configuration settings.
To import and use HTTPException:
import { Hono } from 'hono'
import { HTTPException } from 'hono/http-exception'
const app = new Hono()
app.post('/auth', async (c, next) => {
const authorized = false // Example check
if (!authorized) {
throw new HTTPException(401, { message: 'Authentication required' })
}
await next()
})HTTPException Options
When creating an HTTPException, you can pass an options object as the second argument:
| Option Key | Type | Description |
|---|---|---|
message | string | Optional custom error message string. |
res | Response | Optional custom Response object to return directly. |
cause | unknown | Optional underlying cause that triggered the error. |
Tip
If you provide a custom Response via the res option, HTTPException automatically applies your status code and headers to that response when rendered.
Customizing Error Responses with .onError()
By default, unhandled errors produce a generic server response. You can capture and format all application errors globally using the .onError() method on your Hono instance.
import { Hono } from 'hono'
const app = new Hono()
app.onError((err, c) => {
console.error(`Execution error: ${err.message}`)
return c.json(
{
error: 'Internal Server Error',
message: err.message,
},
500
)
})
app.get('/fail', () => {
throw new Error('Something went wrong!')
})Customizing 404 Not Found Responses
When a request matches no defined routes, Hono triggers its fallback Not Found handler. You can customize this response across your application using the .notFound() method.
import { Hono } from 'hono'
const app = new Hono()
app.notFound((c) => {
return c.json({ error: 'Resource not found', path: c.req.path }, 404)
})
app.get('/hello', (c) => c.text('Hello!'))You can also trigger a Not Found response manually inside any handler using the Context helper:
app.get('/check', (c) => {
const item = null
if (!item) {
return c.notFound()
}
return c.text('Found')
})Accessing Errors in Middleware via Context
Middleware functions can inspect whether an error occurred further down the execution chain by checking c.error. This is useful for logging, cleanup tasks, or custom post-processing logic.
import { Hono } from 'hono'
const app = new Hono()
app.use('*', async (c, next) => {
await next()
if (c.error) {
console.warn(`Captured error on path ${c.req.path}: ${c.error.message}`)
}
})Note
c.error holds the error object thrown by handlers or preceding middleware during the request lifecycle.