create-t3-app: bug: 7.22.0 next build error TRPCClientError: Dynamic server usage

Provide environment information

“ct3aMetadata”: { “initVersion”: “7.22.0” },

Describe the bug

image

Reproduction repo

.

To reproduce

when:

  • install: pnpm create t3-app@latest
  • use nextjs appdir option
  • build: pnpm build

Additional information

No response

About this issue

  • Original URL
  • State: closed
  • Created 8 months ago
  • Reactions: 11
  • Comments: 30 (3 by maintainers)

Commits related to this issue

Most upvoted comments

e? Technically, this issue is resolved and should be closed, but obviously the behavior you’re experiencing is problematic.

Just did a pull of the repo today and was still getting the bug mentioned by OP, in just the base T3 app. I have been reading a ton of these threads and managed to find a few work arounds, but they all seem like a rather quick fix Band-Aid than an actual solution.

Is there any recommendation by the T3 team on how to bypass this error or is it safe to ignore because the app still technically builds?

+1 on this bug report, I’m running node v20.9.0 The issue is also present when deploying to Vercel

Switching from node 18 to 20 fixes this for me

Doesn’t work for me

Update: was spreading misinformation, still no real solution. Edited with comments.

@c-ehrlich While I have no idea why it happens, like you said, here is some info from my limited testing, that I hope proves useful. 😃

I can see that using TRPCReactProvider on a layout level produces a DYNAMIC_SERVER_USAGE error as it is unable to produce the entire page statically due to a use of headers.

When I instead move the provider elsewhere, and only have it wrap the actual components that wish to access ~/trpc/react, the error disappears as it is now limiting the dynamicness only to a certain component. It ain’t pretty, as it requires us to wrap components. In this scenario I didn’t have to resort to forcing dynamic, it seems to be able to decide on its own.

~What I do for now is move the TRPCReactProvider into page.tsx, and have it only in pages that actually have components that use it. Feels like an ok solution for now.~ Not an ok solution, as it forces the entire page into a λ state instead of a SSG.

Now, not saying this is a solution but leaving this here hoping it is helpful to someone, until we find a better one…

~All the while, ~/trpc/server works just fine without a need of a provider, and produces no errors. :)~ No idea what happened there, it most definitely produces errors during build, due to using headers in the server render phase. The file server.ts uses next/headers const heads = new Map(headers()); which causes the error we see. Replacing it with new Headers() helps pass the error, but fails to actually fetch data due to ECONNREFUSED while fetching

P.S. Not sure how wrapping each element in TRPCReactProvider affects memory and that stuff, so there is also a secondary option instead of having to throw a kazzilion TRPCReactProvider around your components. We did this pattern very often when it comes to shared state, contexts and providers - conditionally wrap the layout ONLY when is client, otherwise print children as-is.

// layout.tsx
    <html lang="en">
      <body>
        <main>
          <WrapOnlyClient
            wrapper={
              <TRPCReactProvider headers={headers()}>
                {children}
              </TRPCReactProvider>
            }
          >
            {children}
          </WrapOnlyClient>
        </main>
      </body>
    </html>

In this scenario, the page will SSR as-is, and will have no provider during SSR, but will actually have a provider in the client, allowing the client components to do their work. The major issue with this is that you then also must ensure that you don’t mount (only) the offending client components during SSR, effectively making them client-only or mounted-only.

// some/page.tsx
<OnlyClient><ContainsTrpcCalls /></OnlyClient>

Thanks for the issue. Can reproduce. Weirdly enough this issue exists for the hello query but not for the query that gets all posts. force-dynamic works as a band-aid, but feels less than optimal. Will research further.

https://github.com/t3-oss/create-t3-app/pull/1567#issuecomment-1748418796

this fix got rid of the issue for me - should it ship with by default?

This seems to be a solution:

https://github.com/orgs/vercel/discussions/4696#discussioncomment-7494345

import { api } from '@/trpc/server';
import { unstable_noStore as noStore } from 'next/cache';

async function getIdeas() {
  noStore();
  const ideas = await api.ideas.getAll.query();
  return ideas;
}

Today, I encountered this issue. Any updates on the fix?

Screenshot 2023-11-19 at 14 40 26

That seems random since it doesn’t appear to be a node issue rather Next throwing a valid error…?

Same issue for me, and the funny thing is it doesn’t happen to all pages. Some pages are completely fine and the setup is exactly the same, just calling for different data from the db. The website still deploys on Vercel and works as expect. This is the only time I see red in deploy log and it still manages to complete the build.

I only found these in the example bundled with t3, I never found it in any of my other projects.

I experimented by splitting all await into its independent components and then wrapping it with Suspense, the error went into the abyss in no time.

I suspect, it’s Next.js trying to make all RSC static by default and only parts of its page are interactable which is dynamic. Whenever Next.js detects headers() or cookies() passed to the component, it normally catches it and makes the page dynamic, this error means, the error isn’t watched properly for some reason.

Wrapping the components in Suspense worked as a temporary solution for me as well.