vercel/next.js · error

Default export is missing in {resource_path}

Error message

Default export is missing in {resource_path}

What it means

Emitted at request time inside the JavaScript that Turbopack generates for a text-based App Router metadata route (e.g. app/robots.ts, app/manifest.ts, app/sitemap.xml without generateSitemaps, app/icon). The generated wrapper imports the route module's default export as `handler` and checks `typeof handler !== 'function'`; if the file has no default-exported function, it throws. Metadata route handlers must default-export a function that returns the route's data.

Source

Thrown at crates/next-core/src/next_app/metadata/route.rs:236

    let stem = stem.unwrap_or_default();

    let content_type = get_content_type(path.clone()).await?;

    // refer https://github.com/vercel/next.js/blob/7b2b9823432fb1fa28ae0ac3878801d638d93311/packages/next/src/build/webpack/loaders/next-metadata-route-loader.ts#L84
    // for the original template.
    let code = formatdoc! {
        r#"
            import {{ NextResponse }} from 'next/server'
            import handler from {resource_path}
            import {{ resolveRouteData }} from
'next/dist/build/webpack/loaders/metadata/resolve-route-data'

            const contentType = {content_type}
            const cacheControl = {cache_control}
            const fileType = {file_type}

            if (typeof handler !== 'function') {{
                throw new Error('Default export is missing in {resource_path}')
            }}

            export async function GET() {{
              const data = await handler()
              const content = resolveRouteData(data, fileType)

              return new NextResponse(content, {{
                headers: {{
                  'Content-Type': contentType,
                  'Cache-Control': cacheControl,
                }},
              }})
            }}

            export * from {resource_path}
        "#,
        resource_path = StringifyJs(&format!("./{}", path.file_name())),
        content_type = StringifyJs(&content_type),

View on GitHub (pinned to 0ae8c72462)

Solutions

  1. Add a default-exported function to the metadata route file that returns the route data.
  2. Confirm the file is a recognized metadata route (correct filename: robots, manifest, sitemap, icon, apple-icon, etc.).
  3. Ensure the default export is a function, not an object or constant.

Example fix

// before: app/robots.ts
export const metadata = { rules: [] }

// after: app/robots.ts
export default function(): MetadataRoute.Robots {
  return { rules: [{ userAgent: '*', allow: '/' }] }
}
Defensive patterns

Strategy: validation

Validate before calling

// Validate a metadata route file has a default function export at author time
// (run in a lint rule or pre-build check)
function assertMetadataDefaultExport(moduleSource: string, file: string) {
  if (!/export\s+default\s+(async\s+)?function/.test(moduleSource)) {
    throw new Error(`${file}: metadata route must default-export a function`)
  }
}

Type guard

const isFunction = (v: unknown): v is (...a: any[]) => any =>
  typeof v === 'function'

Try / catch

null

Prevention

When it happens

Trigger: A metadata route file (app/robots.ts, app/manifest.ts, app/sitemap.xml, app/<name>.txt) that exports only named exports, has no default export, or default-exports a non-function (object, string).

Common situations: Copying a Pages Router API route pattern (named exports); writing a config object instead of a function; forgetting the default export; refactoring that renamed/removed it.

Related errors


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