honojs/hono · error · DetailedError
${_fetchRes.status} ${_fetchRes.statusText}
Error message
${_fetchRes.status} ${_fetchRes.statusText} What it means
fetchRP is Hono's tiny RPC/fetch client. After optionally consuming the response body, it checks `response.ok` and throws a DetailedError whose message is the HTTP status line (e.g. "404 Not Found"), attaching statusCode, parsed body data, and statusText. This is how non-2xx responses surface to the caller.
Source
Thrown at src/client/fetch-result-please.ts:34
_data: any
/**
* @description BodyInit property from whatwg-fetch polyfill
*
* @link https://github.com/JakeChampion/fetch/blob/main/fetch.js#L238
*/
_bodyInit?: any
}
const hasBody =
(_fetchRes.body || _fetchRes._bodyInit) && !nullBodyResponses.has(_fetchRes.status)
if (hasBody) {
const responseType = detectResponseType(_fetchRes)
_fetchRes._data = await _fetchRes[responseType]()
}
if (!_fetchRes.ok) {
throw new DetailedError(`${_fetchRes.status} ${_fetchRes.statusText}`, {
statusCode: _fetchRes?.status,
detail: {
data: _fetchRes?._data,
statusText: _fetchRes?.statusText,
},
})
}
return _fetchRes._data
}
export class DetailedError extends Error {
/**
* Additional `message` that will be logged AND returned to client
*/
public detail?: any
/**
* Additional `code` that will be logged AND returned to clientView on GitHub (pinned to e2740d5a1b)
Solutions
- Inspect the caught DetailedError: `err.statusCode` and `err.detail.data` usually contain the server's error body — log them to find the real cause
- Fix the route/method/URL to match the server-side definition (verify with the typed client or a manual curl)
- Add auth headers or middleware that was omitted
- Add error-handling middleware (app.onError) on the server so 500s return meaningful JSON
- If a proxy is involved, check its logs/config for the failing upstream
Example fix
// before
const res = await client.hello.$get()
const data = await res.json() // throws '404 Not Found' via fetchRP
// after
try {
const res = await client.hello.$get()
} catch (e) {
if (e instanceof DetailedError) console.error(e.statusCode, e.detail.data)
throw e
} Defensive patterns
Strategy: try-catch
Type guard
import { DetailedError } from 'hono/client/fetch-result-please'
// (or duck-type)
const isDetailedHttpError = (e: unknown): e is { statusCode?: number; detail?: unknown } =>
typeof (e as any)?.statusCode === 'number' Try / catch
try {
const res = await client.posts.$get()
} catch (e) {
if (typeof (e as any)?.statusCode === 'number') {
const { statusCode, detail } = e as any
if (statusCode === 404) /* missing route */
else if (statusCode >= 500) /* server-side, maybe retry */
else /* 4xx: inspect detail.data for validation info */
}
throw e
} Prevention
- Always await RPC calls inside try/catch; non-2xx throws rather than returning res.ok=false
- Log e.detail.data — it carries the server's error body
- Keep client and server route definitions in sync via the shared AppType type
When it happens
Trigger: Any request where the server responds with a 4xx/5xx status: hitting a wrong RPC route/path, missing route method, auth failure (401/403), validation failure (400/422), server error (500), or a proxy returning an error page.
Common situations: RPC client/server route mismatch after refactoring; forgetting to await an error-handling middleware; gateway timeouts behind reverse proxies; calling endpoints requiring auth without credentials; the HTML error pages of dev proxies being returned instead of JSON.
Understand the failure class
Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.
Related errors
AI-assisted analysis of honojs/hono@e2740d5a1b (2026-08-28).
Data as JSON: /api/errors/7d839efc84f9c61d.
Report an issue: GitHub.