vercel/next.js · error · Error

Both ${MIDDLEWARE_FILENAME} file "./${path.relative(cwd, mid

Error message

Both ${MIDDLEWARE_FILENAME} file "./${path.relative(cwd, middlewareFilePath)}" and ${PROXY_FILENAME} file "./${path.relative(cwd, proxyFilePath)}" are detected. Please use "./${path.relative(cwd, proxyFilePath)}" only. Learn more: https://nextjs.org/docs/messages/middleware-to-proxy

What it means

Thrown by the dev bundler setup when both a middleware convention file (middleware.{ts,js,...}) and a proxy convention file (proxy.{ts,js,...}) exist at the convention level. The proxy file replaces middleware; having both is ambiguous and the dev server refuses to start.

Source

Thrown at packages/next/src/server/lib/router-utils/setup-dev-bundler.ts:490

        }

        const { name: fileBaseName, dir: fileDir } = path.parse(fileName)

        const isAtConventionLevel =
          fileDir === dir || fileDir === path.join(dir, 'src')

        if (isAtConventionLevel && fileBaseName === MIDDLEWARE_FILENAME) {
          middlewareFilePath = fileName
        }
        if (isAtConventionLevel && fileBaseName === PROXY_FILENAME) {
          proxyFilePath = fileName
        }

        if (middlewareFilePath) {
          if (proxyFilePath) {
            const cwd = process.cwd()

            throw new Error(
              `Both ${MIDDLEWARE_FILENAME} file "./${path.relative(cwd, middlewareFilePath)}" and ${PROXY_FILENAME} file "./${path.relative(cwd, proxyFilePath)}" are detected. Please use "./${path.relative(cwd, proxyFilePath)}" only. Learn more: https://nextjs.org/docs/messages/middleware-to-proxy`
            )
          }
          Log.warnOnce(
            `The "${MIDDLEWARE_FILENAME}" file convention is deprecated. Please use "${PROXY_FILENAME}" instead.\n\n` +
              `  To migrate automatically, run:\n` +
              `  npx @next/codemod@canary middleware-to-proxy .\n\n` +
              `  Learn more: https://nextjs.org/docs/messages/middleware-to-proxy`
          )
        }

        const meta = knownFiles.get(fileName)

        const watchTime = fileWatchTimes.get(fileName)
        const nextWatchTime = meta?.timestamp
        // If the file is showing up for the first time or the meta.timestamp is changed since last time
        // Files that were created before we started watching are not considered changed.
        // If any file was created by Next.js while booting, we assume those changes

View on GitHub (pinned to 0ae8c72462)

Solutions

  1. Delete the middleware.{ts,js} file and keep only proxy.{ts,js}, moving its logic over.
  2. Run the official codemod: npx @next/codemod@canary middleware-to-proxy .
  3. Verify only one of the two files remains at the project root or src/ level.

Example fix

// before: both files exist
// src/middleware.ts
// src/proxy.ts

// after: remove middleware, keep proxy
// rm src/middleware.ts
// src/proxy.ts (contains the migrated logic)
Defensive patterns

Strategy: validation

Validate before calling

import { glob } from 'glob'
const hasMiddleware = glob.sync('{src/,}middleware.{ts,tsx,js,jsx}').length > 0
const hasProxy = glob.sync('{src/,}proxy.{ts,tsx,js,jsx}').length > 0
if (hasMiddleware && hasProxy) throw new Error('Remove middleware file; keep proxy')

Type guard

function hasSingleConvention(files: string[]): boolean {
  const mw = files.some(f => /(^|\/)middleware\./.test(f))
  const px = files.some(f => /(^|\/)proxy\./.test(f))
  return !(mw && px)
}

Try / catch

null

Prevention

When it happens

Trigger: After upgrading to a Next.js version that renamed/added the proxy convention, a project has both src/middleware.ts and src/proxy.ts (or root-level equivalents) present. setup-dev-bundler detects both and throws.

Common situations: Upgrading Next.js where middleware was deprecated in favor of proxy, and the migration was started but the old middleware file wasn't removed. Codemod run partially.

Related errors


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