#5345·hono

RegExpRouter: wildcard routes don't match paths containing an encoded line terminator (%0A, %0D)

Author: adeightonCreated Sep 6, 2026Updated Sep 6, 2026

What version of Hono are you using?

4.13.7

What runtime/platform is your app running on? (with version if possible)

Node.js v24.20.0 with @hono/node-server, but the reproduction below uses app.request(), so it looks runtime-independent.

What steps can reproduce the bug?

javascript
import { Hono } from 'hono'

const app = new Hono()
app.get('/*', (c) => c.text('matched'))

console.log((await app.request('/a%20b')).status) // 200
console.log((await app.request('/a%0Ab')).status) // 404  <- expected 200

getPath() runs the path through decodeURI before routing, so %0A becomes a real newline. RegExpRouter compiles a wildcard to ONLY_WILDCARD_REG_EXP_STR = '.*' (and TAIL_WILDCARD_REG_EXP_STR = '(?:|/.*)'), and in JavaScript . never matches a line terminator unless the s flag is set. The route therefore cannot match and the request falls through to the not-found handler.

Named parameters are not affected, because LABEL_REG_EXP_STR = '[^/]+' does match those characters:

javascript
app.get('/:p', (c) => c.text('matched')) // '/a%0Ab' -> 200

I ran into this with a route that accepts free text in a path segment: any text containing a newline 404s, while everything else works.

What is the expected behavior?

A wildcard route matches any path, including one whose decoded form contains a line terminator, the same way a named parameter already does.

What do you see instead?

A 404 from the not-found handler. The route handler is never called.

The affected characters are exactly the four JavaScript line terminators: \n (%0A), \r (%0D), \u2028 (%E2%80%A8) and \u2029 (%E2%80%A9). Tab, form feed, vertical tab and NUL all match fine.

With app.get('/*', ...) and a request to /a%0Ab:

Router Result
SmartRouter (default) 404
RegExpRouter 404
TrieRouter 200
PatternRouter 200
LinearRouter 200

SmartRouter cannot route around this. It selects a router on the first request and only moves on when add() throws UnsupportedPathError; RegExpRouter registers the route without complaint and merely fails to match later, which is indistinguishable from a genuine 404.

Only the wildcard patterns are affected. A wildcard in the middle of a path, such as /files/*/download, compiles to LABEL_REG_EXP_STR and matches correctly.

Additional information

new Hono({ router: new TrieRouter() }) is a working workaround.

A fix might be to make the wildcard patterns match line terminators, for example '[\s\S]*' in place of '.*' and '(?:|/[\s\S]*)' in place of '(?:|/.*)', or to compile the matcher with the s flag.