Next.js Discord

Discord Forum

Error: Cookies can only be modified in a Server Action... but it is a server action?

Answered
David L. Bowman posted this in #help-forum
Open in Discord
Avatar
I cannot seem to delete all my cookies from a server action, I get the following error: [ Server ] Error: Cookies can only be modified in a Server Action or Route Handler. Read more: https://nextjs.org/docs/app/api-reference/functions/cookies#options

// page.tsx
import { CreatePatientForm } from "@/components/CreatePatientForm";
import { deleteAllCookies } from "@/lib/next/deleteAllCookies";

export default async function Home() {
    await deleteAllCookies();

    return (
        <main className="min-h-screen flex items-center justify-center bg-gray-100">
            <CreatePatientForm />
        </main>
    );
}

// deleteAllCookies.ts
"use server";

import { cookies } from "next/headers";

export async function deleteAllCookies() {
    const cookieStore = await cookies();
    for (const cookie of cookieStore.getAll()) {
        cookieStore.delete(cookie.name);
    }
}
Answered by B33fb0n3
when fetching your own endpoints inside a server component, you need to provide the full url from the api route instead of a relative url like you doing rn

In every case it's not recommended to fetch your own api routes. You want to delete all your cookies now. Why you would want to do that is unclear to me. It is not recommended. For more information read this: https://nextjs-faq.com/fetch-api-in-rsc
View full answer

20 Replies

Avatar
when you calling your server action inside a server component, the server action will be translated to a normal function. And with that it's just a normal function.

You can only modify your cookies inside a server action or route handler. So do that and you will be good to go
Avatar
Hmmm, that makes sense. Although, when I try to manipulate the cookies directly within the server component /page.tsx I get the same error:

"use server";

import { CreatePatientForm } from "@/components/CreatePatientForm";
import { cookies } from "next/headers";

export default async function Home() {
    const cookieStore = await cookies();
    for (const cookie of cookieStore.getAll()) {
        cookieStore.delete(cookie.name);
    }

    return (
        <main className="min-h-screen flex items-center justify-center bg-gray-100">
            <CreatePatientForm />
        </main>
    );
}
Avatar
yea, beeing inside a server component doesn't mean, that you are inside a server action or route handler.

You need to be inside a server action (call a server function from the client for example) or use a route handler
Avatar
I'm sorry, I don't understand. Could you tell me what I'm doing wrong? When I look at the documentation, it looks like I'm doing nearly the exact same thing.
import { CreatePatientForm } from "@/components/CreatePatientForm";
import { cookies } from "next/headers";

export default async function Home() {
    const cookieStore = await cookies();
    for (const cookie of cookieStore.getAll()) {
        cookieStore.delete(cookie.name);
    }

    return (
        <main className="min-h-screen flex items-center justify-center bg-gray-100">
            <CreatePatientForm />
        </main>
    );
}
Image
Maybe it doesn't like my delete function.
Avatar
you are right, you doing nearly exactly what's written down. There is one difference:

Server components: READ cookies (modifications are NOT allowed)
Server action or route handler: READ, MODIFY cookies (modifications are allowed)

What do you need to do?
Remove the deletion (modify) of your cookies.
Avatar
Okay, that makes sense. Then... how do I delete my cookies? When I try to call a server action like:
"use server";

import { cookies } from "next/headers";

export async function deleteAllCookies() {
    const cookieStore = await cookies();
    for (const cookie of cookieStore.getAll()) {
        cookieStore.delete(cookie.name);
    }
}

From within the /page.tsx it doesn't work. Where am I supposed to call this function?
Image
I really appreciate your help btw.
Image
Avatar
don't use a server action here as it will be automatically translated to a normal function. Use a route handler instead
Avatar
Okay, so... this may be the last thing, and I appreciate you teaching me.

Here's my /app/api/deleteAllCookies/route.ts
import { cookies } from "next/headers";

export async function DELETE(request: Request) {
    const cookieStore = await cookies();
    for (const cookie of cookieStore.getAll()) {
        cookieStore.delete(cookie.name);
    }

    return new Response("Cookies Deleted", {
        status: 200,
    });
}

// page.tsx
import { CreatePatientForm } from "@/components/CreatePatientForm";

export default async function Home() {
    await fetch("/api/deleteAllCookies", {
        method: "DELETE",
    });

    return (
        <main className="min-h-screen flex items-center justify-center bg-gray-100">
            <CreatePatientForm />
        </main>
    );
}
Image
Avatar
when fetching your own endpoints inside a server component, you need to provide the full url from the api route instead of a relative url like you doing rn

In every case it's not recommended to fetch your own api routes. You want to delete all your cookies now. Why you would want to do that is unclear to me. It is not recommended. For more information read this: https://nextjs-faq.com/fetch-api-in-rsc
Answer
Avatar
Thank you, you taught me a lot of things, This works perfectly for me now.
I'm creating a demo app for a client, and I need them to reset their cookies every time they start the app.
Honestly, i should have just created a db.
Maybe this is still bad practice.
Avatar
then it's the best to create a page.tsx for that that imports a client component with a button "clear all cookies". On the button click a server action will be called to delete all cookies.

As the server action is called from a client component, the server action works fine. It also doesn't happen on every request then
Avatar
I can do this, a better idea.
Avatar
happy to help
Avatar
i appreciated learning more about this though 🙂