#97·G0DM0D3

Express 5: /v1/research/batch/* route throws PathError at registration, and req.params[0] is undefined

Author: rattusrattusCreated Sep 4, 2026Updated Sep 4, 2026

api/routes/research.ts registers the batch-file route with a bare wildcard and reads it positionally:

typescript
researchRoutes.get('/batch/*', async (req, res) => {
  const filePath = req.params[0]

package.json pins express: ^5.2.1. Express 5 moved to path-to-regexp v8, which requires a named wildcard and exposes it by name rather than by index, so both lines are affected.

Reproduction

Against the repo's own installed Express (5.2.1):

javascript
const express = require('express')
const r = express.Router()
r.get('/batch/*', (q, s) => s.end())
PathError: Missing parameter name at index 8: /batch/*

A named wildcard registers fine, and shows why the second line also needs changing:

javascript
app.get('/batch/*splat', (req, res) => res.json({
  keys: Object.keys(req.params),      // ["splat"]
  zero: req.params[0],                // undefined
  splat: req.params.splat,            // "metadata/batch_2024-01-01_0001.jsonl"
}))

So there are two failures in one handler: the route throws when it is registered, and even if it registered, req.params[0] would be undefined and the handler would return its own 400 Invalid batch path.

Suggested fix

typescript
researchRoutes.get('/batch/*splat', async (req, res) => {
  const sp = (req.params as any).splat
  const filePath = Array.isArray(sp) ? sp.join('/') : (sp || '')

splat is a string for a single-segment match and an array in some cases, so joining covers both. The existing validation (.jsonl suffix and the ^(metadata|dataset)/batch_[\w.-]+\.jsonl$ test) is unchanged and still does the path-traversal work.

I have been running exactly this patch locally against f630176 and the endpoint serves batch files correctly with it.

Environment: f630176 (main), express 5.2.1, Node 24.11.0, Windows.