Fix 'Missing parameter name at 1' in Express 5 routes
Your Express 5 server crashes at start-up. One changed route string brings it back, and on current installs the message itself names the route to change.
TL;DR#
Express 5 parses every route path with path-to-regexp 8, where * is a wildcard that needs a name, exactly like :id. A bare *, as in app.all('*', …), app.get('/*', …) or the app.options('*', cors()) line from the cors README, has no name, so Express throws while it registers the route, which in a typical app is before app.listen() is reached. Name the wildcard: app.all('/{*splat}', …) matches every path, / included. For a 404 fallback you can also drop the path and register app.use((req, res) => …) after every other route. Prisma, TypeScript and your Node.js version play no part in it.
One error, two wordings#
The Stack Overflow question is titled with the source line Node prints above the stack trace. The asker's code is an Express and Prisma API written in TypeScript, and the accepted answer changes one line, the fallback route: app.all('*', …) becomes app.all('/{*any}', …).
What you see depends on which path-to-regexp release npm installed under Express. The outputs and test results in this article were reproduced on 6 October 2026 in a throwaway node:24-alpine container (Node.js v24.21.0, npm 11.19.0). The test app has a health route and the question's 404 fallback, with a log line on each side of the fallback:
const express = require('express');
const app = express();
app.get('/health', (req, res) => res.json({ ok: true }));
console.log('registering the 404 fallback');
app.all('*', (req, res) => {
res.status(404).json({ error: 'Not found', path: req.path, params: req.params });
});
console.log('fallback registered');
app.listen(3000, () => console.log('listening on 3000'));Up to path-to-regexp 8.2.0, the version pinned here with npm overrides, Node prints the line from the question's title and a plain TypeError that gives only a position:
/srv/api-ptr820/node_modules/path-to-regexp/dist/index.js:73
throw new TypeError(`Missing parameter name at ${i}: ${DEBUG_URL}`);
^
TypeError: Missing parameter name at 1: https://git.new/pathToRegexpErrorSince path-to-regexp 8.3.0 (2 September 2025, "Add custom error class" and "Improved error messages and stack size"), the error is a PathError, a subclass of TypeError, and the message carries the position, the path itself and a link. A plain npm install express resolved to express 5.2.1, router 2.2.0 and path-to-regexp 8.4.2, and the same app printed:
/srv/api/node_modules/path-to-regexp/dist/index.js:108
throw new PathError(`Missing parameter name at index ${index}`, str);
^
PathError [TypeError]: Missing parameter name at index 1: *; visit https://git.new/pathToRegexpError for info
at consumeUntil (/srv/api/node_modules/path-to-regexp/dist/index.js:108:27)
at parse (/srv/api/node_modules/path-to-regexp/dist/index.js:140:26)
at process (/srv/api/node_modules/path-to-regexp/dist/index.js:263:56)
at pathToRegexp (/srv/api/node_modules/path-to-regexp/dist/index.js:274:5)
at Object.match (/srv/api/node_modules/path-to-regexp/dist/index.js:225:30)
at matcher (/srv/api/node_modules/router/lib/layer.js:86:23)
at new Layer (/srv/api/node_modules/router/lib/layer.js:93:62)
at router.route (/srv/api/node_modules/router/index.js:428:17)
at app.route (/srv/api/node_modules/express/lib/application.js:257:22)
at app.all (/srv/api/node_modules/express/lib/application.js:495:20) {
originalPath: '*'
}The number is the same in both wordings: the position just after the * or : that has no name, counted from zero. It tells you what kind of path to look for even on the older message. One route per run on Express 5.2.1:
| Route path | Message on path-to-regexp 8.4.2 |
|---|---|
'*' | Missing parameter name at index 1: * |
'/*' | Missing parameter name at index 2: /* |
'/api/*' | Missing parameter name at index 6: /api/* |
'/users/:' | Missing parameter name at index 8: /users/: |
Why Express 5 rejects an unnamed wildcard#
Express 5 hands routing to the router package, and router@2.2.0 depends on path-to-regexp ^8.0.0 (npm registry, checked on the same day), while Express 4.22.3 still uses path-to-regexp 0.1.13. Version 8 is a different syntax for paths: :name is a parameter, *name is a wildcard that matches one or more characters across segments, and braces mark an optional part. The path-to-regexp README says a parameter name must follow : or *, and Express's migration guide applies that to wildcards, with /*splat as the replacement for /* and /{*splat} when the root path must match too.
The error fires when the route is registered, not when a request arrives. app.all() creates a router layer, and the layer compiles its path in its constructor: the stack above runs from app.all through new Layer into the parser. In the reproduction, the log line written just before app.all('*', …) printed, the one just after it never did, nor did the listening on 3000 callback, and the process exited with code 1. That is why the error shows up at start-up or on deploy rather than as a 500 on a request.
The reason for the change is on record. In the issue asking for app.all('*') back, path-to-regexp's maintainer explains that the syntax was changed for compatibility with proxies and path rewriting, such as rewriting /api/*path to /api/v1/*path, and that Express 4's * caused many edge cases because it was confused with regular-expression syntax.
The timing explains the wave of reports. Express 5.0.0 shipped in September 2024, but npm kept Express 4 as latest until the Express 5.1.0 announcement on 31 March 2025, three days before the question was asked. Since then npm install express with no version installs Express 5: in the reproduction it wrote "express": "^5.2.1" into package.json. Code written for Express 4, tutorials and README snippets included, fails on its first unnamed wildcard. The same announcement lists the new path syntax among the breaking changes that need manual edits, and the v5 migration recipe in the official codemod repository has no transform for route strings, so running it does not fix this error.
Fix: name every wildcard, or drop the path#
1. Find the route the message is about#
From path-to-regexp 8.3.0 the message names the path (*, /api/*). The stack trace may not name your file: Node keeps 10 frames by default, and for the app.all('*') above, Express, router and path-to-regexp used all ten, ending inside express/lib/application.js. On 8.2.0 the ten frames did not even reach Express. Raise the limit for one run:
node --stack-trace-limit=50 app.jsFor a nameless wildcard declared in routes/files.js, the message and the two frames that point into the project were:
PathError [TypeError]: Missing parameter name at index 8: /files/*; visit https://git.new/pathToRegexpError for info
at Object.<anonymous> (/srv/api/routes/files.js:5:8)
at Object.<anonymous> (/srv/api/app.js:2:15)To list the commonest candidates, the strings that end in *, search your sources (GNU grep; BusyBox grep in Alpine images rejects --exclude-dir):
grep -rnE --exclude-dir=node_modules --include='*.js' --include='*.ts' "\*['\"]" .On a test tree it listed router.get('/files/*', …) and app.options('*', cors()), plus cors({ origin: '*' }), which is not a route and can stay. It did not match '/{*splat}' or '/docs/*splat', which both register. It also missed three paths that throw the same error, because their * or : is followed by . or / rather than a quote: '/assets/*.js' (index 9), '/a/*/b' (index 4) and '/users/:' (index 8). For those, the path in the error message is your pointer.
2. Give the wildcard a name#
splat is only a name: any JavaScript identifier works, which is why the accepted answer's '/{*any}' is equivalent. The braces are what matter: they make the wildcard optional, which lets the route match the root path. Each line below was tested on Express 5.2.1:
| Express 4 path | Express 5 path | What it matched |
|---|---|---|
'*' | '/{*splat}' | every path, / included |
'/*' | '/*splat' | every path except / |
'/api/*' | '/api/*splat' | /api/v1/users, not /api or /api/ |
'/api/*' | '/api{/*splat}' | /api, /api/ and /api/v1/users |
'/:file.:ext?' | '/:file{.:ext}' | /image and /image.png |
Express 4's '/*' also matched /: the migration guide's Express 4 example shows GET / giving { '0': '' }. Where the root must keep matching, use '/{*splat}' rather than '/*splat'.
For the question's catch-all, the one-line change in the test app is:
app.all('/{*splat}', (req, res) => {
res.status(404).json({ error: 'Not found', path: req.path, params: req.params });
});3. For a 404 handler, drop the path entirely#
The Express FAQ handles 404s with a middleware function at the very bottom of the stack and no path argument, so there is no wildcard to name:
import express, { type Request, type Response } from 'express';
const app = express();
app.get('/health', (req: Request, res: Response) => {
res.json({ ok: true });
});
app.use((req: Request, res: Response) => {
res.status(404).json({ error: 'Not found', path: req.path });
});
app.listen(3000);Like app.all, it answers every method: GET /, GET /no/such/page and DELETE /api/gadgets/42 all got the JSON 404 in the reproduction. It has to stay last, because a route registered after it is never reached.
4. Replace app.options('*', cors())#
On 6 October 2026 the cors README still showed app.options('*', cors()) for enabling pre-flight across the board, and on Express 5 that line throws Missing parameter name at index 1: *. The same README notes that app.use(cors()) already handles pre-flight requests for all routes, which needs no path:
const express = require('express');
const cors = require('cors');
const app = express();
app.use(cors());
app.delete('/api/gadgets/:id', (req, res) => res.json({ deleted: req.params.id }));
app.listen(3000);With cors 2.8.6, this version and app.options('/{*splat}', cors()) both answered the pre-flight with 204 and access-control-allow-origin: *. Deleting the line without adding either is not a fix: the pre-flight then came back 200 with no Access-Control-Allow-Origin header, which the browser treats as a failed CORS check. If the browser now reports has been blocked by CORS policy, continue with Fix: blocked by CORS policy from origin localhost:3000, which explains why the header has to come from the server and how a global app.use(cors()) also answers the OPTIONS pre-flight for every route.
5. Update handlers that read the old wildcard value#
On Express 4.22.3 the control run put the whole matched path in req.params[0] ("/no/such/page"). On Express 5, req.params[0] no longer exists: a named wildcard is an array of segments (["no","such","page"]), and with /{*splat} it is absent altogether when / matches, as the migration guide documents for unmatched parameters. If the handler only needs the path, req.path returned the same value on both versions:
app.all('/{*splat}', (req, res) => {
const segments = req.params.splat ?? [];
res.status(404).json({ error: 'Not found', path: req.path, segments });
});Verify the server starts and answers#
Start the app and check that it reaches its listen callback, then request the root, a missing path and a non-GET method. With the change from step 2, the test app answered, one request per line:
GET /health -> 200 {"ok":true}
GET / -> 404 {"error":"Not found","path":"/","params":{}}
GET /no/such/page -> 404 {"error":"Not found","path":"/no/such/page","params":{"splat":["no","such","page"]}}
POST /api/gadgets/42 -> 404 {"error":"Not found","path":"/api/gadgets/42","params":{"splat":["api","gadgets","42"]}}On your own machine, curl -i http://localhost:3000/no/such/page should return your own 404 body rather than a crash or Express's default Cannot GET page. The grep from step 1 is a shortcut, not a proof: the real check is that the app starts, since any nameless * or : it missed throws again at start-up, with its path in the message on path-to-regexp 8.3.0 and later.
Do not count on the compiler to catch a regression. TypeScript 7.0.2 with @types/express 5.0.6 compiled app.all('*', …) with exit code 0, and accepted req.params.splat as string[] | undefined in a '/docs/{*splat}' route: the path syntax is only checked when Express registers the route. The throw happens as soon as the module that registers the route runs, so a test that merely imports that module fails with the same message, before a single request.
When the error survives the accepted answer#
The accepted answer fixes the one route in the question. If the crash continues, another route still has a nameless * or :, and the path or the index in the message tells you which. Other places it hides: app.use('*', …) (index 1), an SPA fallback app.get('/*', …) that sends index.html (index 2, the case discussed in expressjs/express#6428), and routes such as /api/* (index 6) inside router files.
Once the wildcards are named, the next crash from the same migration can be an Express 4 optional parameter. app.get('/files/:name?', …) threw a different message, Unexpected ? at index 12: /files/:name?, with the same link. Braces replace the question mark: '/files{/:name}' matched both /files and /files/report.pdf.
The third answer on the question uses app.all('*id', …), a wildcard with a name but no leading slash. It registers and it matches /, but the array starts with an empty segment: ["",""] for / and ["","no","such","page"] for /no/such/page. '/{*splat}' gives cleaner values for the same coverage.
The second answer went back to Express 4 (4.21.2). That works: Express 4.22.3, with path-to-regexp 0.1.13, started with app.all('*') and answered both / and /no/such/page. Express's version support page still lists 4.x as supported, but only the latest release of each major line is, so stay on the latest 4.x (npm install express@4 installed 4.22.3) rather than an exact older release. It postpones the change; the routes still need their names on the way to Express 5. In expressjs/express#6428, an Express maintainer gave related advice: name the major version you rely on, as in npm install express@5, so the next major does not arrive the same way.
Prisma and TypeScript are bystanders#
Most of the asker's code is Prisma (findMany, create, findUnique, update), which makes the question look like an ORM problem. The reproduction installed no Prisma at all and crashed the same way, because the throw happens while routes are registered, before any request could reach a Prisma call.
Two things are still worth a look once the server starts. The controller casts req.query.status to the Prisma enum with as Status, which TypeScript accepts without checking the value at run time; How to Get Enums in Prisma Client validates enum input in an Express route with Zod instead. And if the first request that reaches Prisma fails with Environment variable not found: DATABASE_URL, that is Prisma configuration, not Express 5, and Prisma: Environment variable not found: DATABASE_URL covers it.
Express 5 did not remove catch-all routes; it made their names mandatory and reports a missing one at start-up, where it is hard to miss. Rename the wildcard, or replace the catch-all with a path-less app.use(), and the routes register again on Express 5; handlers that read req.params[0] still need the change in step 5.
Further reading: npm WARN requires a peer of X but none is installed: fix. Also see Fix dyld "missing symbol called" in Node on an M1 Mac. Also see Fix nvm use "exit status 1: Access is denied" on Windows.
Frequently Asked Questions
Still stuck? Paste your error.
Paste the error message or stack trace — we check it against every fix and tool on the site.
One email a month — the latest explained errors
What the site published that month — mostly Next.js, Supabase and Node errors, explained. You confirm by email; unsubscribe any time in one click.
Continue Reading
Fix MikroORM: global EntityManager instance is disallowed
A fresh MikroORM 5/6 project throws a ValidationError on the first em.create() call. Here is why the global EntityManager is blocked, and the two ways to fix it properly.
Fix Vite 'global is not defined': shim or move fs code
Why each define line only reveals the next error with fs-extra (reproduced on Vite 2.9.5), which shim works for Buffer-based libraries on Vite 2 and 8, and how to type it.
Fix dyld "missing symbol called" in Node on an M1 Mac
Find which of Node, the compiled addon and the system library is on the wrong CPU architecture, line them up, and know what the follow-up errors mean.


