honojs/hono · warning · HTTPException

Malformed JSON in request body

Error message

Malformed JSON in request body

What it means

The validator middleware with type 'json' calls c.req.json(), which throws when the request body is not valid JSON. The middleware converts that into an HTTPException with status 400 and the message 'Malformed JSON in request body'.

Source

Thrown at src/validator/validator.ts:102

  E extends Env = any,
>(
  target: U,
  validationFunc: VF
): MiddlewareHandler<E, P, V, ExtractValidationResponse<VF>> => {
  return async (c, next) => {
    let value = {}
    const contentType = c.req.header('Content-Type')

    switch (target) {
      case 'json':
        if (!contentType || !jsonRegex.test(contentType)) {
          break
        }
        try {
          value = await c.req.json()
        } catch {
          const message = 'Malformed JSON in request body'
          throw new HTTPException(400, { message })
        }
        break
      case 'form': {
        if (
          !contentType ||
          !(multipartRegex.test(contentType) || urlencodedRegex.test(contentType))
        ) {
          break
        }

        let formData: FormData

        if (c.req.bodyCache.formData) {
          formData = await c.req.bodyCache.formData
        } else {
          try {
            const arrayBuffer = await c.req.arrayBuffer()
            formData = await bufferToFormData(arrayBuffer, contentType)

View on GitHub (pinned to e2740d5a1b)

Solutions

  1. Reproduce with curl sending the exact body and validate it with a JSON linter
  2. Ensure the client sets body to JSON.stringify(obj) with Content-Type: application/json
  3. If the client sends form data, switch the route validator to type 'form' or 'multipart'
  4. Return a clearer 400 handler via app.onError for HTTPException to expose parse details in dev

Example fix

// before (client)
fetch(url, { body: formData }) // route expects json
// after
fetch(url, { headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(obj) })
Defensive patterns

Strategy: validation

Validate before calling

// client-side: ensure valid JSON before sending
const body = JSON.stringify(obj)
await fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body })

Type guard

const isJsonParseable = (s: string): boolean => { try { JSON.parse(s); return true } catch { return false } }

Try / catch

app.onError((err, c) => { if (err instanceof HTTPException && err.status === 400) return c.json({ error: 'bad request', message: err.message }, 400) throw err })

Prevention

When it happens

Trigger: A request with Content-Type: application/json (or no type match for form) whose body is invalid JSON — trailing commas, single quotes, unquoted keys, HTML error pages, empty body, or form data sent with a JSON content type.

Common situations: Frontend sending FormData or urlencoded data while route validates as 'json'; client concatenating JSON fragments; proxies returning HTML error pages; missing body on POST; BOM or text/plain payloads parsed as JSON.

Understand the failure class

Related errors


AI-assisted analysis of honojs/hono@e2740d5a1b (2026-08-28). Data as JSON: /api/errors/4e2cc613710fbe20. Report an issue: GitHub.