Next.js Discord

Discord Forum

Throwing errors from server actions only send `digest` to client

Unanswered
declspecl posted this in #help-forum
Open in Discord
Hi all!
I'm using next 14 and supabase in my project, and I have a server action that creates a board. The procedure first uploads the user selected picture to storage and then creates the board in the database. In both cases, if supabase returns an error to me, I immediately throw it. It looks like this:
"use server";

export async function createBoard(formData: FormData) {
    // ...
    const { data: uploadedPictureURL, error: pictureUploadError} = await supabase.storage.from("board-pictures")
        .upload(boardPicture.name, boardPicture);

    if (pictureUploadError)
        throw new Error(`Failed to upload picture to storage: ${pictureUploadError.message}`);
    // ...

Then, I have a client component form who defines a middleman action to do input validation and show the user proper error messages:
"use client";

export function CreateBoardForm() {
    // ...
    async function createBoardClientAction(formData: FormData) {
        try {
            await createBoard(formData); // the server action defined above
        }
        catch (error) {
            console.error(error);

            setError(error);
        }
    }

    return (
        <form action={createBoardClientAction}>
            <input type="text" placeholder="Board name" name="boardName" />

            <input type="file" accept="image/png, image/jpeg" name="boardPicture" />

            <button type="submit">Create</button>

            <p>{error ? JSON.stringify(error) : "safe"}</p>
        </form>
    );
}

But when this error happens, the error object only has digest, not message, i.e: {"digest":"2489054772"} and I have no idea why. Many examples in the nextjs docs show throwing errors in server actions, but never using them. Also, thrown errors from form actions just totally halt your site with an error message, so im starting to think I should just return { data, error } instead of throwing. Thoughts and help are much appreciated, thanks!

2 Replies

Morelet’s Crocodile
The error object only having a digest property instead of a message suggests that the error object is not being properly constructed or passed along in the server action. It's possible that the error message is not being assigned to the error object correctly.

One possible solution is to modify the server action code to explicitly set the error message when throwing an error. For example:

"use server";

export async function createBoard(formData: FormData) {
// ...
const { data: uploadedPictureURL, error: pictureUploadError} = await supabase.storage.from("board-pictures")
.upload(boardPicture.name, boardPicture);

if (pictureUploadError) {
const errorMessage = Failed to upload picture to storage: ${pictureUploadError.message};
throw new Error(errorMessage);
}
// ...
}
By explicitly setting the error message, you can ensure that it is included in the thrown error object and can be accessed in the client component.

Alternatively, you could modify the server action to return an object with both the data and error properties, instead of throwing an error. This way, you can handle the error in the client component without halting the site. For example:

"use server";

export async function createBoard(formData: FormData) {
// ...
const { data: uploadedPictureURL, error: pictureUploadError} = await supabase.storage.from("board-pictures")
.upload(boardPicture.name, boardPicture);

if (pictureUploadError) {
return { data: null, error: Failed to upload picture to storage: ${pictureUploadError.message} };
}
// ...
}
In the client component, you can then check if the returned object has an error property and handle it accordingly.

Overall, the approach you choose depends on your specific requirements and how you want to handle errors in your application.
@Morelet’s Crocodile The error object only having a digest property instead of a message suggests that the error object is not being properly constructed or passed along in the server action. It's possible that the error message is not being assigned to the error object correctly. One possible solution is to modify the server action code to explicitly set the error message when throwing an error. For example: "use server"; export async function createBoard(formData: FormData) { // ... const { data: uploadedPictureURL, error: pictureUploadError} = await supabase.storage.from("board-pictures") .upload(boardPicture.name, boardPicture); if (pictureUploadError) { const errorMessage = `Failed to upload picture to storage: ${pictureUploadError.message}`; throw new Error(errorMessage); } // ... } By explicitly setting the error message, you can ensure that it is included in the thrown error object and can be accessed in the client component. Alternatively, you could modify the server action to return an object with both the data and error properties, instead of throwing an error. This way, you can handle the error in the client component without halting the site. For example: "use server"; export async function createBoard(formData: FormData) { // ... const { data: uploadedPictureURL, error: pictureUploadError} = await supabase.storage.from("board-pictures") .upload(boardPicture.name, boardPicture); if (pictureUploadError) { return { data: null, error: `Failed to upload picture to storage: ${pictureUploadError.message}` }; } // ... } In the client component, you can then check if the returned object has an error property and handle it accordingly. Overall, the approach you choose depends on your specific requirements and how you want to handle errors in your application.
ive already tried chatgpt but thanks anyways