next.js: [NEXT-428] AppDir: Static Page generation and build process fails for Dynamic Routes with Fetch (in Version >= 13.1.2)

Verify canary release

  • I verified that the issue exists in the latest Next.js canary release

Provide environment information

Operating System:
  Platform: linux
  Arch: x64
  Version: #45~20.04.1-Ubuntu SMP Mon Apr 4 09:38:31 UTC 2022
Binaries:
  Node: 16.15.1
  npm: 8.11.0
  Yarn: 1.22.19
  pnpm: N/A
Relevant packages:
  next: 13.1.3-canary.4
  eslint-config-next: N/A
  react: 18.2.0
  react-dom: 18.2.0

Which area(s) of Next.js are affected? (leave empty if unsure)

App directory (appDir: true), Data fetching (gS(S)P, getInitialProps)

Link to the code that reproduces this issue

https://codesandbox.io/s/build-with-dynamic-routes-fails-in-next-13-1-2-ei0ms2

To Reproduce

Open a new terminal in the sandbox and runnpm run build

Describe the Bug

To generate the static pages, next fetches with [dynamic] as the query param. So instead of https://swapi.dev/api/people/1/?format=json it fetches https://swapi.dev/api/people/[dynamic]/?format=json.

In my production environment, that query can’t be handled by the API, no json is returned, or the JSON doesn’t match the promise (as you would expect), leading the build process to fails. The api in the code sandbox should return {"detail":"Not found"} for the incorrect call, but it also says: Error: Failed to fetch data.

This worked as intended in 13.1.1 and below.

Even if you catch these errors and the build process is successful, that should leave you with a static page without your desired data.

This will leave you with the following trace:

> build
> next build

warn  - You have enabled experimental feature (appDir) in next.config.js.
warn  - Experimental features are not covered by semver, and may cause unexpected or broken application behavior. Use at your own risk.
info  - Thank you for testing `appDir` please leave your feedback at https://nextjs.link/app-feedback

info  - Creating an optimized production build
info  - Compiled successfully
info  - Linting and checking validity of types
info  - Collecting page data
[=   ] info  - Generating static pages (0/4)https://swapi.dev/api/people/%5Bdynamic%5D/?format=json
[==  ] info  - Generating static pages (3/4)Error: Failed to fetch data
    at getData (/sandbox/.next/server/app/[dynamic]/page.js:146:15)
    at processTicksAndRejections (node:internal/process/task_queues:96:5)
    at async Page (/sandbox/.next/server/app/[dynamic]/page.js:151:18)
[Error: An error occurred in the Server Components render. The specific message is omitted in production builds to avoid leaking sensitive details. A digest property is included on this errorinstance which may provide additional details about the nature of the error.] {
  digest: '2682591503'
}

Error occurred prerendering page "/[dynamic]". Read more: https://nextjs.org/docs/messages/prerender-error
Error: Failed to fetch data
    at getData (/sandbox/.next/server/app/[dynamic]/page.js:146:15)
    at processTicksAndRejections (node:internal/process/task_queues:96:5)
    at async Page (/sandbox/.next/server/app/[dynamic]/page.js:151:18)
info  - Generating static pages (4/4)

> Build error occurred
Error: Export encountered errors on following paths:
        /[dynamic]/page: /[dynamic]
    at /sandbox/node_modules/next/dist/export/index.js:409:19
    at processTicksAndRejections (node:internal/process/task_queues:96:5)
    at async Span.traceAsyncFn (/sandbox/node_modules/next/dist/trace/trace.js:79:20)
    at async /sandbox/node_modules/next/dist/build/index.js:1398:21
    at async Span.traceAsyncFn (/sandbox/node_modules/next/dist/trace/trace.js:79:20)
    at async /sandbox/node_modules/next/dist/build/index.js:1258:17
    at async Span.traceAsyncFn (/sandbox/node_modules/next/dist/trace/trace.js:79:20)
    at async Object.build [as default] (/sandbox/node_modules/next/dist/build/index.js:66:29)

Expected Behavior

According to the docs, dynamic routes will cause Next.js to render the whole route dynamically, at request time. Not sure if next just always tries to generatestatic pages as well, but this should not make the build process fail.

Which browser are you using? (if relevant)

No response

How are you deploying your application? (if relevant)

No response

NEXT-428

About this issue

  • Original URL
  • State: closed
  • Created a year ago
  • Reactions: 7
  • Comments: 19 (10 by maintainers)

Most upvoted comments

Imo, having to use export const dynamic = 'force-dynamic'; feels like an unnecessary step to me. If the route path contains ‘[]’ it is clearly a dynamic route and should be considered as such by default. Again, this was working in 13.1.1.

If we need to have this for some other reason, may be it would be worth mentioning it in https://beta.nextjs.org/docs/routing/defining-routes#dynamic-segments

@JJ can you verify this issue?

I could definitely give it a try, but it’s going to be faster trying and find the right person-whose-nick-starts-with-JJ-or-maybe-just-J 🤣

My problem is probably the same, although the error message is different:

@lukasnevosad my guess is that somewhere in your page component, you’re throwing an uncaught error for the invalid linkId.

From the error message, it looks like somewhere you’re validating the linkId and if it’s not valid, throwing new Error('Invalid linkId "%5BlinkId%5D");'. Try wrapping the contents of your function / render()method intry { … } catch(e) { …}and returnnotFound()(which you can import fromnext/navigation`) instead of letting the error leave your component uncaught. My guess is that will solve your problem.

If you don’t want to leverage the static page generation for that route and you’re not using generateStaticParams anyway, you can also add export const dynamic = 'force-dynamic'; but I think handling the error is good practice anyway.

Specifically, if you manually hit /l/[linkId], I suspect you’re getting an HTTP 500 error which is a little blunt. Handling the error and returning notFound() would return an HTTP 404 which I feel is a little more appropriate.

TL;DR:

  • add export const dynamic = 'force-dynamic'; to dynamic routes without generateStaticParams
  • expect dynamic routes to receive dummy params equal to the parameter name (e.g. { slug: '[slug]' })
  • upgrade to v13.1.3-canary.5 or later

I ran into this issue. Specifically, it began to happen between v13.1.1 and v13.1.2.

The error in the console was a little convoluted, but the pertinent line is this:

Error occurred prerendering page "/blog/[slug]". Read more: https://nextjs.org/docs/messages/prerender-error

Between the aforementioned versions, the number of static pages that next build was trying to generated increased by 4 - also the same number of routes I have with dynamic components (e.g. [slug]).

The root cause appears to be that starting with v13.1.2, the build process attempts to generate pages for those routes where it hadn’t done before. Since generateStaticParams isn’t defined, it sends through dummy data equal to the parameter name, [slug] in my case. My page component (defined in /app/blog/[slug]/page.tsx) wasn’t gracefully handling the dummy value and was throwing an uncaught error.

The suggested fix of adding export const dynamic = 'force-dynamic'; to that file did not work in v13.1.2, however it did in v13.1.3. It seems that the fix does begin working in v13.1.3-canary.5, so I suspect #45015 was the solution.

Since it only happened on that one route and not my other dynamic routes (which also don’t have generateStaticParams or export const dynamic = 'force-dynamic'; specified), the underlying issue was my uncaught error (accessing a property on undefined).

That said, even in the latest non-canary version (v13.1.5), I still get the same issue without export const dynamic = 'force-dynamic';. Perhaps there’s an opportunity to clarify in the documentation what is causing this error (and the potential fix)?