honojs/hono · error · Error

Unmet condition

Error message

Unmet condition

What it means

This error is thrown by Hono's combine() middleware when a wrapped condition middleware returns exactly false, signaling its condition was not met. every() wraps each middleware so that a boolean false return is converted into an 'Unmet condition' Error; this lets you express allOf-style routing where all conditions must pass. It is a control-flow signal used with combine/every/some, not a bug indicator by itself.

Source

Thrown at src/middleware/combine/index.ts:109

 *   myCheckLocalNetwork(),
 *   every(
 *     bearerAuth({ token }),
 *     myRateLimit({ limit: 100 }),
 *   ),
 * ));
 * ```
 */
export const every = (...middleware: (MiddlewareHandler | Condition)[]): MiddlewareHandler => {
  return async function every(c, next) {
    const currentRouteIndex = c.req.routeIndex
    await compose(
      middleware.map((m) => [
        [
          async (c: Context, next: Next) => {
            c.req.routeIndex = currentRouteIndex // should be unchanged in this context
            const res = await m(c, next)
            if (res === false) {
              throw new Error('Unmet condition')
            }
            return res
          },
        ],
      ])
    )(c, next)
  }
}

/**
 * Create a composed middleware that runs all middleware except when the condition is met.
 *
 * @param condition - A string or Condition function.
 * If there are multiple targets to match any of them, they can be passed as an array.
 * If a string is passed, it will be treated as a path pattern to match.
 * If a Condition function is passed, it will be evaluated against the request context.
 * @param middleware - A composed middleware
 *

View on GitHub (pinned to e2740d5a1b)

Solutions

  1. Make the condition middleware return true (or undefined/Response) when the condition passes so every() proceeds
  2. If partial matches should pass, use some(...) instead of every(...) so any single true suffices
  3. Ensure condition helpers return booleans, not 'false' strings or 0 which may behave unexpectedly
  4. Wrap routes so condition-mismatched requests fall through to other handlers instead of erroring (order routes/middleware appropriately)

Example fix

// before
const middleware = every(
  (c, next) => { return c.req.header('x-version') === '2' } // false → throws 'Unmet condition'
)

// after
const middleware = every(
  (c, next) => {
    if (c.req.header('x-version') !== '2') return c.text('Wrong version', 400)
    return next()
  }
)
Defensive patterns

Strategy: try-catch

Try / catch

try {
  await app.request(req)
} catch (err) {
  if (err instanceof Error && err.message === 'Unmet condition') {
    return new Response('Condition not met', { status: 400 })
  }
  throw err
}

Prevention

When it happens

Trigger: Using every(...) with a condition middleware (e.g. from hono/combine or custom predicates) that returns false for the current request; chaining conditionals where one middleware evaluates the request (path, header, query) and returns false to reject it; using some(...) incorrectly when you meant all conditions to be required.

Common situations: Custom guard middleware returning false (e.g. checking an API version header), combining basename/pathname matchers where one doesn't match, expecting false-returning middleware to just skip downstream handling instead of throwing.

Related errors


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