[트러블슈팅] cookies was called outside a request scope 오류 해결

조아영·2024년 10월 15일

❌ Error: cookies was called outside a request scope.

🚨 문제

// server.tsx
import { createServerClient } from "@supabase/ssr";
import { cookies } from "next/headers";

export function createClient() {
    const cookieStore = cookies();

    return createServerClient(process.env.NEXT_PUBLIC_SUPABASE_URL!, process.env.NEXT_PUBLIC_SUPABASE_KEY!, {
        cookies: {
            getAll() {
                return cookieStore.getAll();
            },
            setAll(cookiesToSet) {
                try {
                    cookiesToSet.forEach(({ name, value, options }) => cookieStore.set(name, value, options));
                } catch {
                    // The `setAll` method was called from a Server Component.
                    // This can be ignored if you have middleware refreshing
                    // user sessions.
                }
            },
        },
    });
}

export const supabase = createClient(); // 🚨 전역에서 supabase 클라이언트를 생성

// server-actions.ts
import { supabase } from "./server"; // 🚨 전역으로 생성한 supabase 클라이언트 사용 중

export async function signin() {
    const { error } = await supabase.auth.signInWithPassword();
    // ...
}

이 코드를 사용해 supabase 클라이언트를 전역에서 생성하려 하자 cookies was called outside a request scope 오류가 발생했다.

🤔 원인

이 오류는 cookies() 함수가 요청(Request)이 있을 때만 사용할 수 있는 함수이기 때문에 발생한다. 전역에서 supabase 클라이언트를 생성하려 하면서, 요청이 없는 상황에서 cookies()가 호출되었고, 그 결과 해당 오류가 발생한 것이다.

Next.js에서 cookies()는 서버에서 클라이언트의 요청에 포함된 쿠키 데이터를 가져오는 함수이다. 따라서 요청이 없을 때 전역에서 cookies()를 호출하면, Request scope가 없기 때문에 해당 함수는 사용할 수 없다.

✅ 해결

해결 방법은 요청이 있을 때마다 새로운 supabase 클라이언트를 생성하는 것이다. 전역에서 클라이언트를 생성하지 말고, 필요한 함수 내에서 매번 클라이언트를 생성하여 요청에 맞는 쿠키 정보를 사용할 수 있도록 한다.

// server.tsx
import { createServerClient } from "@supabase/ssr";
import { cookies } from "next/headers";

export function createClient() {
    const cookieStore = cookies();

    return createServerClient(process.env.NEXT_PUBLIC_SUPABASE_URL!, process.env.NEXT_PUBLIC_SUPABASE_KEY!, {
        cookies: {
            getAll() {
                return cookieStore.getAll();
            },
            setAll(cookiesToSet) {
                try {
                    cookiesToSet.forEach(({ name, value, options }) => cookieStore.set(name, value, options));
                } catch {
                    // The `setAll` method was called from a Server Component.
                    // This can be ignored if you have middleware refreshing
                    // user sessions.
                }
            },
        },
    });
}

// ✅ 전역에서 불러오지 않음

// server-actions.ts
import { createClient } from "./server"; // ✅ createClient 함수를 불러옴

export async function signin() {
    const supabase = createClient(); // ✅ 요청마다 새로운 클라이언트를 생성
    const { error } = await supabase.auth.signInWithPassword();
    // ...
}

정리: Next.js에서는 요청마다 필요한 데이터를 가져와야 하기 때문에, 쿠키나 세션 같은 정보는 전역에서 다루기 어렵다. 따라서 요청이 있을 때마다 새로운 클라이언트를 생성해서 요청에 맞는 데이터를 처리하는 것이 안전하다.

0개의 댓글