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
- Make the condition middleware return true (or undefined/Response) when the condition passes so every() proceeds
- If partial matches should pass, use some(...) instead of every(...) so any single true suffices
- Ensure condition helpers return booleans, not 'false' strings or 0 which may behave unexpectedly
- 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
- Condition middleware should return true/undefined/Response, reserving false for intentional rejection
- Choose every() vs some() deliberately: AND vs OR semantics
- Keep condition predicates pure and unit-test them against sample requests
- Return a Response from guards when you want a specific status instead of an error
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
- next() called multiple times
- Context is not finalized. Did you forget to return a Respons
- basic auth middleware requires options for "username and pas
- bearer auth middleware requires options for "token" or "veri
- Middleware vary configuration cannot include "*", as it disa
AI-assisted analysis of honojs/hono@e2740d5a1b (2026-08-28).
Data as JSON: /api/errors/7cb7b0fce2536aa9.
Report an issue: GitHub.