Files
gh-jezweb-claude-skills-ski…/references/top-errors.md
2025-11-30 08:25:04 +08:00

12 KiB

Next.js 16 - Top 18 Errors & Solutions

Last Updated: 2025-10-24 Prevention Rate: 100% (all documented errors caught)

This guide covers the 18 most common errors when using Next.js 16 and their solutions.


Error #1: params is a Promise

Error Message:

Type 'Promise<{ id: string }>' is not assignable to type '{ id: string }'

Cause: Next.js 16 changed params to async.

Solution:

// ❌ Before (Next.js 15)
export default function Page({ params }: { params: { id: string } }) {
  const id = params.id
}

// ✅ After (Next.js 16)
export default async function Page({ params }: { params: Promise<{ id: string }> }) {
  const { id } = await params
}

TypeScript Fix:

type Params<T = Record<string, string>> = Promise<T>

Error #2: searchParams is a Promise

Error Message:

Property 'query' does not exist on type 'Promise<{ query: string }>'

Cause: searchParams is now async in Next.js 16.

Solution:

// ❌ Before
export default function Page({ searchParams }: { searchParams: { q: string } }) {
  const query = searchParams.q
}

// ✅ After
export default async function Page({ searchParams }: { searchParams: Promise<{ q: string }> }) {
  const { q: query } = await searchParams
}

Error #3: cookies() requires await

Error Message:

'cookies' implicitly has return type 'any'

Cause: cookies() is async in Next.js 16.

Solution:

// ❌ Before
import { cookies } from 'next/headers'

export function MyComponent() {
  const cookieStore = cookies()
  const token = cookieStore.get('token')
}

// ✅ After
import { cookies } from 'next/headers'

export async function MyComponent() {
  const cookieStore = await cookies()
  const token = cookieStore.get('token')
}

Error #4: headers() requires await

Error Message:

'headers' implicitly has return type 'any'

Cause: headers() is async in Next.js 16.

Solution:

// ❌ Before
import { headers } from 'next/headers'

export function MyComponent() {
  const headersList = headers()
}

// ✅ After
import { headers } from 'next/headers'

export async function MyComponent() {
  const headersList = await headers()
}

Error #5: Parallel route missing default.js

Error Message:

Error: Parallel route @modal/login was matched but no default.js was found

Cause: Next.js 16 requires default.js for all parallel routes.

Solution:

// Create app/@modal/default.tsx
export default function ModalDefault() {
  return null
}

Structure:

app/
├── @modal/
│   ├── login/
│   │   └── page.tsx
│   └── default.tsx  ← REQUIRED

Error #6: revalidateTag() requires 2 arguments

Error Message:

Expected 2 arguments, but got 1

Cause: revalidateTag() API changed in Next.js 16.

Solution:

// ❌ Before (Next.js 15)
import { revalidateTag } from 'next/cache'
revalidateTag('posts')

// ✅ After (Next.js 16)
import { revalidateTag } from 'next/cache'
revalidateTag('posts', 'max') // Second argument required

Cache Life Profiles:

  • 'max' - Maximum staleness (recommended)
  • 'hours' - Stale after hours
  • 'days' - Stale after days
  • Custom: { stale: 3600, revalidate: 86400 }

Error #7: Cannot use React hooks in Server Component

Error Message:

You're importing a component that needs useState. It only works in a Client Component

Cause: Using React hooks in Server Component.

Solution: Add 'use client' directive:

// ✅ Add 'use client' at the top
'use client'

import { useState } from 'react'

export function Counter() {
  const [count, setCount] = useState(0)
  return <button onClick={() => setCount(count + 1)}>{count}</button>
}

Error #8: middleware.ts is deprecated

Warning Message:

Warning: middleware.ts is deprecated. Use proxy.ts instead.

Solution: Migrate to proxy.ts:

# 1. Rename file
mv middleware.ts proxy.ts

# 2. Rename function
# middleware → proxy

Code:

// ✅ proxy.ts
export function proxy(request: NextRequest) {
  // Same logic
}

Error #9: Turbopack build failure

Error Message:

Error: Failed to compile with Turbopack

Cause: Turbopack is now default in Next.js 16.

Solution 1 (opt-out):

npm run build -- --webpack

Solution 2 (fix compatibility): Check for incompatible packages and update them.


Error #10: Invalid next/image src

Error Message:

Invalid src prop (https://example.com/image.jpg) on `next/image`. Hostname "example.com" is not configured

Cause: Remote images not configured.

Solution: Add to next.config.ts:

const config = {
  images: {
    remotePatterns: [
      {
        protocol: 'https',
        hostname: 'example.com',
        pathname: '/images/**',
      },
    ],
  },
}

Error #11: Cannot import Server Component into Client Component

Error Message:

You're importing a Server Component into a Client Component

Cause: Direct import of Server Component in Client Component.

Solution: Pass as children:

// ❌ Wrong
'use client'
import { ServerComponent } from './server-component'

export function ClientComponent() {
  return <ServerComponent />
}

// ✅ Correct
'use client'

export function ClientComponent({ children }: { children: React.ReactNode }) {
  return <div>{children}</div>
}

// Usage
<ClientComponent>
  <ServerComponent /> {/* Pass as children */}
</ClientComponent>

Error #12: generateStaticParams not working

Error Message:

generateStaticParams is not generating static pages

Cause: Missing dynamic = 'force-static'.

Solution:

export const dynamic = 'force-static'

export async function generateStaticParams() {
  const posts = await fetch('/api/posts').then(r => r.json())
  return posts.map((post: { id: string }) => ({ id: post.id }))
}

Error #13: fetch() not caching

Error Message: Data not cached (performance issue).

Cause: Next.js 16 uses opt-in caching.

Solution: Add "use cache":

'use cache'

export async function getPosts() {
  const response = await fetch('/api/posts')
  return response.json()
}

Error #14: Route collision with Route Groups

Error Message:

Error: Conflicting routes: /about and /(marketing)/about

Cause: Route groups creating same URL path.

Solution: Ensure unique paths:

app/
├── (marketing)/about/page.tsx     → /about
└── (shop)/store-info/page.tsx     → /store-info (NOT /about)

Error #15: Metadata not updating

Error Message: SEO metadata not showing correctly.

Cause: Using static metadata for dynamic pages.

Solution: Use generateMetadata():

export async function generateMetadata({ params }: { params: Promise<{ id: string }> }): Promise<Metadata> {
  const { id } = await params
  const post = await fetch(`/api/posts/${id}`).then(r => r.json())

  return {
    title: post.title,
    description: post.excerpt,
  }
}

Error #16: next/font font not loading

Error Message: Custom fonts not applying.

Cause: Font variable not applied to HTML element.

Solution:

import { Inter } from 'next/font/google'

const inter = Inter({ subsets: ['latin'], variable: '--font-inter' })

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html className={inter.variable}> {/* ✅ Apply variable */}
      <body>{children}</body>
    </html>
  )
}

Error #17: Environment variables not available in browser

Error Message: process.env.SECRET_KEY is undefined in client.

Cause: Server-only env vars not exposed to browser.

Solution: Prefix with NEXT_PUBLIC_:

# .env
SECRET_KEY=abc123                  # Server-only
NEXT_PUBLIC_API_URL=https://api    # Available in browser
// Server Component (both work)
const secret = process.env.SECRET_KEY
const apiUrl = process.env.NEXT_PUBLIC_API_URL

// Client Component (only public vars)
const apiUrl = process.env.NEXT_PUBLIC_API_URL

Error #18: Server Action not found

Error Message:

Error: Could not find Server Action

Cause: Missing 'use server' directive.

Solution:

// ❌ Before
export async function createPost(formData: FormData) {
  await db.posts.create({ ... })
}

// ✅ After
'use server'

export async function createPost(formData: FormData) {
  await db.posts.create({ ... })
}

Quick Error Lookup

Error Type Solution Link
Async params Add await params #1
Async searchParams Add await searchParams #2
Async cookies() Add await cookies() #3
Async headers() Add await headers() #4
Missing default.js Create default.tsx #5
revalidateTag 1 arg Add cacheLife argument #6
Hooks in Server Component Add 'use client' #7
middleware.ts deprecated Rename to proxy.ts #8
Turbopack failure Use --webpack flag #9
Invalid image src Add remotePatterns #10
Import Server in Client Pass as children #11
generateStaticParams Add dynamic = 'force-static' #12
fetch not caching Add 'use cache' #13
Route collision Use unique paths #14
Metadata not updating Use generateMetadata() #15
Font not loading Apply font variable to <html> #16
Env vars in browser Prefix with NEXT_PUBLIC_ #17
Server Action not found Add 'use server' #18

Prevention Checklist

Before deploying, check:

  • All params are awaited
  • All searchParams are awaited
  • All cookies() calls are awaited
  • All headers() calls are awaited
  • All parallel routes have default.js
  • revalidateTag() has 2 arguments
  • Client Components have 'use client'
  • middleware.ts migrated to proxy.ts
  • Remote images configured in next.config.ts
  • Server Components not imported directly in Client Components
  • Static pages have dynamic = 'force-static'
  • Cached components have 'use cache'
  • No route collisions with Route Groups
  • Dynamic pages use generateMetadata()
  • Fonts applied to <html> or <body>
  • Public env vars prefixed with NEXT_PUBLIC_
  • Server Actions have 'use server'
  • Node.js version is 20.9+

Debugging Tips

Enable TypeScript Strict Mode

// tsconfig.json
{
  "compilerOptions": {
    "strict": true,
    "noUncheckedIndexedAccess": true
  }
}

Check Build Output

npm run build

Look for warnings and errors in build logs.

Use Type Checking

npx tsc --noEmit

Check Runtime Logs

npm run dev

Watch console for errors and warnings.


Resources