vercel/next.js · error

--routes cannot be empty

Error message

--routes cannot be empty

What it means

Thrown by parseRoutes (benchmark.ts:136) when --routes was provided but, after splitting on commas, trimming, and filtering falsy entries, the list is empty. The default route suite (lines 114-127) is only used when --routes is omitted entirely; an explicit but empty --routes is treated as a user error rather than silently falling back to defaults.

Source

Thrown at bench/render-pipeline/benchmark.ts:136

      '/dashboard',
      '/docs',
      '/blog',
      '/streaming/light',
      '/streaming/medium',
      '/streaming/heavy',
      '/streaming/chunkstorm',
      '/streaming/wide',
      '/streaming/bulk',
    ]
  }

  const routes = rawRoutes
    .split(',')
    .map((route) => route.trim())
    .filter(Boolean)

  if (routes.length === 0) {
    throw new Error('--routes cannot be empty')
  }

  for (const route of routes) {
    if (!route.startsWith('/')) {
      throw new Error(`Each route must start with '/': ${route}`)
    }
  }

  return routes
}

function usage() {
  console.log(`Usage: pnpm bench:render-pipeline [options]

Options:
  --scenario=e2e|minimal-server                  (default: e2e)
    e2e:            Real production server (next build + next start).
    minimal-server: NextServer with minimalMode, no router-server.

View on GitHub (pinned to 0ae8c72462)

Solutions

  1. Omit --routes entirely to use the built-in stress suite, or provide at least one route like --routes=/.
  2. If templating from an env var, guard it: only add --routes when the var is non-empty.
  3. Check for stray commas or whitespace-only values.
  4. Confirm each entry is a path you intend to benchmark.

Example fix

# before
#   pnpm bench:render-pipeline --routes="$ROUTES"   # with ROUTES unset

# after
if [ -n "$ROUTES" ]; then
  pnpm bench:render-pipeline --routes="$ROUTES"
else
  pnpm bench:render-pipeline   # use built-in defaults
fi
Defensive patterns

Strategy: validation

Validate before calling

function nonEmptyRoutesArg(raw: string | undefined): string[] | undefined {
  if (raw === undefined) return undefined // use defaults
  const routes = raw.split(',').map((r) => r.trim()).filter(Boolean)
  if (routes.length === 0) throw new Error('--routes parsed to empty; omit the flag to use defaults')
  return routes
}

Type guard

function isNonEmptyRouteList(raw: string | undefined): boolean {
  if (raw === undefined) return true
  return raw.split(',').map((r) => r.trim()).filter(Boolean).length > 0
}

Try / catch

try {
  const routes = parseRoutes(args.get('routes'))
} catch (err) {
  if ((err as Error).message === '--routes cannot be empty') {
    console.error('Pass at least one route (e.g. --routes=/) or omit --routes to use defaults.')
    process.exit(2)
  }
  throw err
}

Prevention

When it happens

Trigger: Passing `--routes=` (empty string -> split yields [''] -> filter(Boolean) yields []), or `--routes=,,,` (only commas/whitespace), or `--routes=" "`. Omitting --routes is fine and uses defaults.

Common situations: A shell variable that was empty expanded into --routes=; a CI script templating routes from an unset env var; user assuming --routes= means 'use defaults'.

Related errors


AI-assisted analysis of vercel/next.js@0ae8c72462 (2026-08-06). Data as JSON: /api/errors/b699638ac3cb2494. Report an issue: GitHub.