Next-auth Session is null on initial render with useSuspenseQuery

This one's been driving me crazy and I would love some help. I can't even work out whether it's TRPC, react query, or next-auth that's causing the issue. I'm using TRPC 11.0.0-rc-682, next-auth 5.0.0-beta.25, and the nextjs 15.1.3 app router. I have a route with an id param:
// src/app/artefacts/[artefactId]/page.tsx
// imports

function Page({ routeParams }: InferPagePropsType<RouteType>) {
const [{ artefactId }, session] = use(Promise.all([routeParams, auth()]))

void trpc.artefacts.getById.prefetch({ artefactId })

return (
<MainContainer>
<ArtefactView artefactId={artefactId} />
</MainContainer>
)
}

export default withParamValidation(Page, Route)
// src/app/artefacts/[artefactId]/page.tsx
// imports

function Page({ routeParams }: InferPagePropsType<RouteType>) {
const [{ artefactId }, session] = use(Promise.all([routeParams, auth()]))

void trpc.artefacts.getById.prefetch({ artefactId })

return (
<MainContainer>
<ArtefactView artefactId={artefactId} />
</MainContainer>
)
}

export default withParamValidation(Page, Route)
ArtefactView is a client component with a useSuspenseQuery:
'use client'

import { useSession } from 'next-auth/react'

import { api } from '~/trpc/client'
import { type ArtefactID } from '~/types'

export const ArtefactView: React.FC<{
artefactId: ArtefactID
}> = ({ artefactId }) => {
const session = useSession().data

const [artefact] = api.artefacts.getById.useSuspenseQuery({ artefactId })

// render
}
'use client'

import { useSession } from 'next-auth/react'

import { api } from '~/trpc/client'
import { type ArtefactID } from '~/types'

export const ArtefactView: React.FC<{
artefactId: ArtefactID
}> = ({ artefactId }) => {
const session = useSession().data

const [artefact] = api.artefacts.getById.useSuspenseQuery({ artefactId })

// render
}
artefacts.getById is protected by middleware that checks for a session and throws an unauthorized error if missing. Navigating to this page from another page works fine, but if I perform a hard refresh I get an unauthorized error and a fall-back to client rendering. I've traced the cause down to the session being null in my protectedProcedure, but only on the initial SSR pass. I'm sure I've messed up the setup code somewhere, but I'm not sure where to look? Any advice is greatly appreciated. I wanted to paste more code here but the character limit won't let me.
Solution:
```typescript // server component export function ServerComponent() { void trpc.procedure.prefetch() ...
Jump to solution
2 Replies
traches
trachesOP2w ago
Sorry, I missed that @conlonj25 posted basically the exact same issue a few days ago, but they didn't share a solution. I've tried wrapping the ArtefactView in a suspense container (inside page.tsx), but that didn't help. Update: I needed a suspense wrapper. I tried that previously, but there was another query deeper in the tree that also needed a prefetch. You have to have this structure:
Solution
traches
traches2w ago
// server component
export function ServerComponent() {
void trpc.procedure.prefetch()

return (
<Suspense><ClientComponent /></Suspense>
)
// server component
export function ServerComponent() {
void trpc.procedure.prefetch()

return (
<Suspense><ClientComponent /></Suspense>
)
'use client'

export function ClientComponent() {
const [data] = api.procedure.useSuspenseQuery()

return // stuff
}
'use client'

export function ClientComponent() {
const [data] = api.procedure.useSuspenseQuery()

return // stuff
}
And you have to prefetch every single suspense query, don't miss any

Did you find this page helpful?