Skip to main content
doc0blade47/honodocumentation home
Sign in

Validation

Last updated Oct 12, 2026100% grounded
Relevant source files

The following files were used as context for generating this wiki page:

Overview

Hono provides a flexible validation middleware via the validator helper src/validator/index.ts:6, enabling developers to inspect, parse, and validate incoming request data across multiple targets including JSON payloads, form data, query parameters, path parameters, headers, and cookies src/validator/validator.ts:9-12, 93-159. By integrating tightly with TypeScript type inference, the validation layer ensures that downstream handlers receive correctly typed input parameters while cleanly separating payload normalization and schema execution src/validator/validator.ts:64-82, 162-170. When validation fails, the system generates structured error responses or dispatches exceptions such as HTTPException to handle malformed inputs src/validator/validator.ts:101-102, 123-125.

Sources: src/validator/index.ts:6, src/validator/validator.ts:9-12, src/validator/validator.ts:64-82, src/validator/validator.ts:93-159, src/validator/validator.ts:162-170, src/validator/validator.ts:101-102, src/validator/validator.ts:123-125

Validator middleware signature and targets

Public Middleware API

The core validation mechanism is exposed through the validator helper function, which accepts a validation target and a validation callback function src/validator/validator.ts:46-88. The function signature leverages generic type parameters to enforce strict type safety between the requested validation target, the input data passed to the callback, and the inferred output type available to subsequent handlers src/validator/validator.ts:46-82.

export const validator = <
  InputType,
  P extends string,
  M extends string,
  U extends ValidationTargetByMethod<M>,
  P2 extends string = P,
  // Capture the actual validation function as a type
  VF extends (
    value: unknown extends InputType ? ValidationTargets[U] : InputType,
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    c: Context<any, P2>
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
  ) => any = (
    value: unknown extends InputType ? ValidationTargets[U] : InputType,
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    c: Context<any, P2>
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
  ) => any,
  V extends {
    in: {
      [K in U]: K extends 'json'
        ? unknown extends InputType
          ? ExtractValidatorOutput<VF>
          : InputType
        : InferInput<ExtractValidatorOutput<VF>, K, FormValue>
    }
    out: { [K in U]: ExtractValidatorOutput<VF> }
  } = {
    in: {
      [K in U]: K extends 'json'
        ? unknown extends InputType
          ? ExtractValidatorOutput<VF>
          : InputType
        : InferInput<ExtractValidatorOutput<VF>, K, FormValue>
    }
    out: { [K in U]: ExtractValidatorOutput<VF> }
  },
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  E extends Env = any,
>(
  target: U,
  validationFunc: VF
): MiddlewareHandler<E, P, V, ExtractValidationResponse<VF>> => {

Sources: src/validator/validator.ts:46-88

The validation function receives the extracted target value and the execution context src/validator/validator.ts:14-22. It may execute synchronously or asynchronously, returning either the transformed output value, a TypedResponse, or a direct Response instance src/validator/validator.ts:14-22.

export type ValidationFunction<
  InputType,
  OutputType,
  E extends Env = {},
  P extends string = string,
> = (
  value: InputType,
  c: Context<E, P>
) => OutputType | TypedResponse | Promise<OutputType> | Promise<TypedResponse>
 

Sources: src/validator/validator.ts:14-23

Supported Validation Targets

Hono supports validation across six distinct request input targets src/validator/validator.ts:93-159. The allowed target keys are constrained based on the HTTP method of the route; specifically, get and head methods prohibit body-containing targets (json and form) src/validator/validator.ts:9-12.

type ValidationTargetKeysWithBody = 'form' | 'json'
type ValidationTargetByMethod<M> = M extends 'get' | 'head' // GET and HEAD request must not have a body content.
  ? Exclude<keyof ValidationTargets, ValidationTargetKeysWithBody>
  : keyof ValidationTargets
 

Sources: src/validator/validator.ts:9-13

Target KeyDescriptionAllowed HTTP Methods
jsonRequest body parsed as JSONAll methods except GET, HEAD
formRequest body parsed as FormData or URL-encoded fieldsAll methods except GET, HEAD
queryURL query string parametersAll methods
paramRoute path parametersAll methods
headerRequest headersAll methods
cookieParsed request cookiesAll methods

Sources: src/validator/validator.ts:9-12, src/validator/validator.ts:93-159

Note

get and head routes restrict ValidationTargetByMethod to exclude body validation targets (form and json), preventing misuse on HTTP verbs that must not carry payload bodies. Sources: src/validator/validator.ts:10-12

Target extraction and decoding mechanisms

Extraction and Parsing Call Sequences

When the validator middleware processes a cookie target, it dispatches execution through a structured utility chain to extract, parse, trim, and decode cookie values [[src/validator/validator.ts:157-159|src/validator/validator.ts:157-159], [src/helper/cookie/index.ts:27-48|src/helper/cookie/index.ts:27-48], [src/utils/cookie.ts:102-138|src/utils/cookie.ts:102-138], [src/utils/url.ts:81-93|src/utils/url.ts:81-93]].

The first call sequence executes: validator → getCookie → parse → trimCookieWhitespace [[src/validator/validator.ts:157-159|src/validator/validator.ts:157-159], [src/helper/cookie/index.ts:27-48|src/helper/cookie/index.ts:27-48], [src/utils/cookie.ts:102-138|src/utils/cookie.ts:102-138], [src/utils/cookie.ts:79-100|src/utils/cookie.ts:79-100]].

  1. validator handles the target switch case for cookie, invoking getCookie(c) src/validator/validator.ts:157-159. Sources: src/validator/validator.ts:157-159
  2. getCookie reads the Cookie header from c.req.raw.headers, and calls parse(cookie) if no specific key is requested src/helper/cookie/index.ts:27-48. Sources: src/helper/cookie/index.ts:27-48
  3. parse splits the cookie string by ;, iterates through each pair, and isolates cookie names and values src/utils/cookie.ts:107-124. Sources: src/utils/cookie.ts:107-124
  4. trimCookieWhitespace strips leading and trailing spaces and tab characters (charCode 0x20 and 0x09) from the parsed cookie name and value substrings [[src/utils/cookie.ts:79-100|src/utils/cookie.ts:79-100], [src/utils/cookie.ts:115|src/utils/cookie.ts:115], [src/utils/cookie.ts:124|src/utils/cookie.ts:124]]. Sources: src/utils/cookie.ts:79-100, src/utils/cookie.ts:115, src/utils/cookie.ts:124

The second call sequence executes: validator → getCookie → parse → tryDecode [[src/validator/validator.ts:157-159|src/validator/validator.ts:157-159], [src/helper/cookie/index.ts:27-48|src/helper/cookie/index.ts:27-48], [src/utils/cookie.ts:102-138|src/utils/cookie.ts:102-138], [src/utils/url.ts:81-93|src/utils/url.ts:81-93]].

  1. validator dispatches to getCookie(c) src/validator/validator.ts:157-159. Sources: src/validator/validator.ts:157-159
  2. getCookie retrieves the raw header and invokes parse(cookie) src/helper/cookie/index.ts:27-48. Sources: src/helper/cookie/index.ts:27-48
  3. parse validates cookie values against validCookieValueRegEx and checks for percent encoding src/utils/cookie.ts:128-130. Sources: src/utils/cookie.ts:128-130
  4. tryDecode attempts to decode percent-encoded cookie values using decodeURIComponent_, gracefully falling back to partial replacements if malformed sequences are encountered [[src/utils/cookie.ts:130|src/utils/cookie.ts:130], [src/utils/url.ts:81-93|src/utils/url.ts:81-93]]. Sources: src/utils/cookie.ts:130, src/utils/url.ts:81-93

Sources: src/validator/validator.ts:157-159, src/helper/cookie/index.ts:27-48, src/utils/cookie.ts:79-138, src/utils/url.ts:81-93

Target Extraction Implementations

Non-cookie targets extract request data directly from the context request wrapper inside the validator switch statement src/validator/validator.ts:93-160. Query parameters map multi-value fields when query arrays exceed a length of one src/validator/validator.ts:144-150.

  case 'query':
    value = Object.fromEntries(
      Object.entries(c.req.queries()).map(([k, v]) => {
        return v.length === 1 ? [k, v[0]] : [k, v]
      })
    )
    break
  case 'param':
    value = c.req.param() as Record<string, string>
    break
  case 'header':
    value = c.req.header()
    break
  case 'cookie':
    value = getCookie(c)
    break
}

Sources: src/validator/validator.ts:144-160

Warning

When parsing cookies or query parameters, tryDecode catches decoding exceptions on malformed percent-encoding and decodes valid segments independently rather than failing the entire request src/utils/url.ts:81-93. Sources: src/utils/url.ts:81-93

Note

getQueryStrings scans the request URL starting at index 8 to locate query parameters, returning an empty string if no query indicator ? is present src/utils/url.ts:136-139. Sources: src/utils/url.ts:136-139

Payload parsing and form normalization

Processing JSON and Form Payloads

When the validator processes a request with target json or form, it first inspects the Content-Type header against explicit regular expression patterns defined in src/validator/validator.ts. JSON payloads require a content type matching jsonRegex, which supports standard application/json types along with structured syntax suffixes. Form payloads accept content types matching either multipartRegex or urlencodedRegex.

const jsonRegex = /^application\/([a-z-\.]+\+)?json(;\s*[a-zA-Z0-9\-]+\=([^;]+))*$/
const multipartRegex = /^multipart\/form-data(;\s?boundary=[a-zA-Z0-9'"()+_,\-./:=?]+)?$/
const urlencodedRegex = /^application\/x-www-form-urlencoded(;\s*[a-zA-Z0-9\-]+\=([^;]+))*$/

Sources: src/validator/validator.ts:24-26

If a request specifies a json target but supplies a malformed body or an unmatching content type, c.req.json() throws an error caught by the validator, which then throws an HTTPException with status code 400 and message 'Malformed JSON in request body'.

try {
  value = await c.req.json()
} catch {
  const message = 'Malformed JSON in request body'
  throw new HTTPException(400, { message })
}

Sources: src/validator/validator.ts:98-103

Warning

Form body parsing checks c.req.bodyCache.formData before consuming the stream. If absent, it reads the request as an ArrayBuffer and transforms it via bufferToFormData, caching the resulting FormData instance on the request object. Sources: src/validator/validator.ts:113-127

FormData Normalization and Key Handling

The form target normalizes raw FormData entries into a structured record using a null-prototype object. During iteration over form fields, keys ending with [] or keys encountering duplicate entries are accumulated into arrays, while single entries populate scalar string or File values.

const form: BodyData<{ all: true }> = Object.create(null)
formData.forEach((value, key) => {
  if (key.endsWith('[]')) {
    ;((form[key] ??= []) as unknown[]).push(value)
  } else if (Array.isArray(form[key])) {
    ;(form[key] as unknown[]).push(value)
  } else if (Object.hasOwn(form, key)) {
    form[key] = [form[key] as string | File, value]
  } else {
    form[key] = value
  }
})

Sources: src/validator/validator.ts:129-140

For broader utility usage outside validation, standalone body parsing via parseBody supports configuration options defined in ParseBodyOptions. These options control array expansion and dot-notation nesting.

OptionTypeDefaultDescription
allbooleanfalseDetermines whether all fields with multiple values should be parsed as arrays
dotbooleanfalseDetermines whether fields with dot notation should be parsed as nested objects

Sources: src/utils/body.ts:43-74

Caution

Nested form value parsing guards against prototype pollution attacks by explicitly ignoring any key paths containing __proto__. Sources: src/utils/body.ts:211-213

Schema validation and execution pipeline

Executing Validation Functions

Once the input data is extracted and parsed according to the target type, the validator invokes the provided validationFunc callback with the assembled value and the active Context instance. This function can be synchronous or asynchronous, returning either a transformed output object, a TypedResponse, a raw Response, or a Promise resolving to any of these types.

export type ValidationFunction<
  InputType,
  OutputType,
  E extends Env = {},
  P extends string = string,
> = (
  value: InputType,
  c: Context<E, P>
) => OutputType | TypedResponse | Promise<OutputType> | Promise<TypedResponse>
 

Sources: src/validator/validator.ts:14-23

const res = await validationFunc(value as never, c as never)
 

Sources: src/validator/validator.ts:162-163

Note

The validation function signature accepts unknown inputs for JSON targets or infers input properties based on third-party schema definitions when using utility helpers. Sources: src/validator/validator.ts:53-63

Handling Validation Outputs

After the validation callback completes, the execution pipeline inspects the returned result to determine whether to short-circuit the request or proceed down the middleware chain. If the result is an instance of Response, the validator immediately returns that response, bypassing subsequent middleware handlers.

if (res instanceof Response) {
  return res as ExtractValidationResponse<VF>
}

Sources: src/validator/validator.ts:164-166

If the validation function returns a transformed output rather than a response object, the validator stores the validated data in the request context using c.req.addValidatedData(target, res) and delegates control to the next handler by calling await next().

c.req.addValidatedData(target, res as never)
 
return (await next()) as ExtractValidationResponse<VF>

Sources: src/validator/validator.ts:168-170

Tip

The ExtractValidatorOutput conditional type helper unwraps promises and strips out Response or TypedResponse union constituents, ensuring type inference correctly isolates the parsed data payload from error responses. Sources: src/validator/validator.ts:175-185

Error response and exception dispatching

Handling Request Payload Exceptions

When parsing incoming request bodies such as JSON or multipart form data, malformed payloads trigger explicit HTTP exceptions that short-circuit request handling. If JSON parsing fails due to syntax errors, the validator catches the exception and raises an HTTPException with status code 400 and a descriptive error message.

try {
  value = await c.req.json()
} catch {
  const message = 'Malformed JSON in request body'
  throw new HTTPException(400, { message })
}

Sources: src/validator/validator.ts:98-103

Similarly, failures encountered during FormData buffer conversion catch the underlying error and construct a 400 status exception combining a base message with the original error details.

try {
  const arrayBuffer = await c.req.arrayBuffer()
  formData = await bufferToFormData(arrayBuffer, contentType)
  c.req.bodyCache.formData = formData
} catch (e) {
  let message = 'Malformed FormData request.'
  message += e instanceof Error ? ` ${e.message}` : ` ${String(e)}`
  throw new HTTPException(400, { message })
}

Sources: src/validator/validator.ts:118-126

Caution

Uncaught exceptions during body consumption throw standardized HTTPException instances with HTTP status 400, preventing internal server crashes from malformed client input. Sources: src/validator/validator.ts:101-102, src/validator/validator.ts:125-125

Custom Response Dispatching

Validation functions can handle failure conditions directly by returning a Response or TypedResponse instance instead of validated data. When the execution pipeline evaluates the result of the validation callback and detects a Response object, it immediately returns that response to the client.

if (res instanceof Response) {
  return res as ExtractValidationResponse<VF>
}

Sources: src/validator/validator.ts:164-166

This mechanism allows schema validation libraries or custom callback handlers to dispatch validation error codes, custom JSON error payloads, or redirection responses without throwing unhandled exceptions.

Tip

Returning a Response from a validation function bypasses c.req.addValidatedData and immediately halts middleware execution, returning the custom response directly. Sources: src/validator/validator.ts:164-166

Was this page helpful?