Next.js Discord

Discord Forum

"Maximum call stack size exceeded" when using Suspense with a Client component

Answered
Spectacled Caiman posted this in #help-forum
Open in Discord
Spectacled CaimanOP
Hello guys! need some backup over here.

I'm trying to stream some data to a client component since I want to do client side filtering (search) from the array I get from an API. I have these two files:
// page.tsx
import { Suspense } from 'react'
import Brands from './brands'
import BrandsSkeleton from './brands-skeleton'
import { getBrands } from '@/lib/pago-movil/get-brands'

export default function AddServicePage() {
  const brandsPromise = getBrands()

  return (
    <div className="container mx-auto py-12 space-y-6">
      <h1 className="text-5xl font-serif">Agregar servicio</h1>

      <Suspense fallback={<BrandsSkeleton />}>
        <Brands brandsPromise={brandsPromise} />
      </Suspense>
    </div>
  )
}

// brands.tsx
'use client'

import { ChevronRight } from 'lucide-react'
import Link from 'next/link'

import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
import { AxiosResponse } from 'axios'
import { type BrandsResponse } from '@/lib/pago-movil/get-brands.types'
import { use } from 'react'

export default function Brands({
  brandsPromise,
}: {
  brandsPromise: Promise<AxiosResponse<BrandsResponse>>
}) {
  const {
    data: { brands },
  } = use(brandsPromise)

  return (
    <div className="grid grid-cols-3 gap-6">
      {brands.map((brand) => (
        <Card key={brand.id}>
          {/* ... */}
        </Card>
      ))}
    </div>
  )
}

I'm following the example in https://nextjs.org/docs/app/getting-started/fetching-data#client-components but I get "Maximum call stack size exceeded".
Any ideas?
Answered by Poodle
The issue is the Axios response object. It has circular references (config, request, etc.) that blow up when React tries to serialize it for streaming to the client.

Don't pass the full Axios promise — extract the data first:
// page.tsx
export default function AddServicePage() {
  const brandsPromise = getBrands().then(res => res.data)
  
  return (
    <Suspense fallback={<BrandsSkeleton />}>
      <Brands brandsPromise={brandsPromise} />
    </Suspense>
  )
}


Then update your types in brands.tsx:
export default function Brands({
  brandsPromise,
}: {
  brandsPromise: Promise<BrandsResponse>  // not AxiosResponse<BrandsResponse>
}) {
  const { brands } = use(brandsPromise)
  // ...
}


The use() hook works fine with promises, but the data being streamed needs to be serializable — plain objects, no circular refs.
View full answer

11 Replies

@Spectacled Caiman Hello guys! need some backup over here. I'm trying to stream some data to a client component since I want to do client side filtering (search) from the array I get from an API. I have these two files: tsx // page.tsx import { Suspense } from 'react' import Brands from './brands' import BrandsSkeleton from './brands-skeleton' import { getBrands } from '@/lib/pago-movil/get-brands' export default function AddServicePage() { const brandsPromise = getBrands() return ( <div className="container mx-auto py-12 space-y-6"> <h1 className="text-5xl font-serif">Agregar servicio</h1> <Suspense fallback={<BrandsSkeleton />}> <Brands brandsPromise={brandsPromise} /> </Suspense> </div> ) } tsx // brands.tsx 'use client' import { ChevronRight } from 'lucide-react' import Link from 'next/link' import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar' import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card' import { AxiosResponse } from 'axios' import { type BrandsResponse } from '@/lib/pago-movil/get-brands.types' import { use } from 'react' export default function Brands({ brandsPromise, }: { brandsPromise: Promise<AxiosResponse<BrandsResponse>> }) { const { data: { brands }, } = use(brandsPromise) return ( <div className="grid grid-cols-3 gap-6"> {brands.map((brand) => ( <Card key={brand.id}> {/* ... */} </Card> ))} </div> ) } I'm following the example in https://nextjs.org/docs/app/getting-started/fetching-data#client-components but I get "Maximum call stack size exceeded". Any ideas?
Poodle
The issue is the Axios response object. It has circular references (config, request, etc.) that blow up when React tries to serialize it for streaming to the client.

Don't pass the full Axios promise — extract the data first:
// page.tsx
export default function AddServicePage() {
  const brandsPromise = getBrands().then(res => res.data)
  
  return (
    <Suspense fallback={<BrandsSkeleton />}>
      <Brands brandsPromise={brandsPromise} />
    </Suspense>
  )
}


Then update your types in brands.tsx:
export default function Brands({
  brandsPromise,
}: {
  brandsPromise: Promise<BrandsResponse>  // not AxiosResponse<BrandsResponse>
}) {
  const { brands } = use(brandsPromise)
  // ...
}


The use() hook works fine with promises, but the data being streamed needs to be serializable — plain objects, no circular refs.
Answer
Spectacled CaimanOP
Oh wow! Interesting 🤔
Alright I’ll try again in an hour or so
@Spectacled Caiman Thank you so much! ✨🤘
Poodle
No problem! Let me know if it works 👍
@Poodle No problem! Let me know if it works 👍
Spectacled CaimanOP
It works! is this something that is kind of well known? 🤔
I looked in google but didn't find anything useful after like 5 minutes
Or maybe the question is how do you know that haha
@Spectacled Caiman It works! is this something that is kind of well known? 🤔
Poodle
Ran into it myself building a Next.js + FastAPI app — Axios responses have circular refs that blow up during serialization. Once you see it once, you never forget haha. Glad it worked!
@Poodle Ran into it myself building a Next.js + FastAPI app — Axios responses have circular refs that blow up during serialization. Once you see it once, you never forget haha. Glad it worked!
Spectacled CaimanOP
Well I was expecting that answer haha.. alright, I'll definitely never forget this 😂 thank you again for your time
@Spectacled Caiman It works! is this something that is kind of well known? 🤔
react serialises anything that goes from server -> client boundary so it might not seem obvious but generally its better to only pass simple values not only to prevent issues like this but to also [save bandwidth](https://github.com/vercel-labs/agent-skills/blob/main/skills/react-best-practices/rules/server-serialization.md)