Next.js Discord

Discord Forum

Handling Requests for Non-existent Static Files in a Multilingual Next.js App (App Router)

Unanswered
bardaxx™ posted this in #help-forum
Open in Discord
Hi everyone,

I’m building a multilingual Next.js 14 app using the App Router (the app/ directory with dynamic [language] and [slug] folders). My folder structure looks like this:

app/
├─ [language]/
│  ├─ [slug]/
│  │  ├─ page.tsx
│  │  └─ not-found.tsx
│  └─ page.tsx         ← language root (e.g. `/en`)
└─ page.tsx            ← fallback for `/`

The issue:
When someone requests a path like: https://mydomain.com/file.zip
Next.js tries to interpret file.zip as the [language] parameter. Because the string contains a . it fails to match the route parameter pattern, throwing:
[Error]: Attribute name "file.zip" contains invalid characters; 
it must match the pattern "^\$?[a-zA-Z0-9_-]+$"

In development, I tried to catch these “bad” requests in layout file logic:

// middleware.ts (development)
const ALLOWED_PATHS = [
  '/favicon.svg',
  '/favicon.ico',
  '/images/',
  // etc.
];

export function middleware(request: NextRequest) {
  const { pathname } = request.nextUrl;

  // Only allow static assets in the whitelist
  const isAllowedPath = ALLOWED_PATHS.some((allowed) =>
    allowed.endsWith('/')
      ? pathname.startsWith(allowed)
      : pathname === allowed
  );
  if (isAllowedPath) {
    return NextResponse.next();
  }

  // Block anything with unusual characters (dots, zip, php, etc.)
  if (/[^a-zA-Z0-9-]/.test(pathname)) {
    return NextResponse.redirect(new URL('/en/not-found', request.url));
  }

  return NextResponse.next();
}

This seemed to work locally (redirecting /file.zip to my custom /en/not-found page), but in production on Vercel it doesn’t—requests still hit the [language] route and crash before middleware can run. I've tried also to implement something like this in middleware with no luck. Any hint?

How can I intercept or short-circuit these requests—whether via middleware, custom route handlers so they return a 404 (or redirect to my not-found page) instead? What’s the recommended pattern?

0 Replies