DX flaw: An error occurred in the Server Components render #66999
Replies: 5 comments 2 replies
-
Beta Was this translation helpful? Give feedback.
-
It's even confusing in the Next.js tutorials: "Seeing these errors are helpful while developing as you can catch any potential problems early." They are not helpful because now devs don't realise the error message they think they're throwing won't displayed in production. But will only work for them while developing. |
Beta Was this translation helpful? Give feedback.
-
Potential solution: |
Beta Was this translation helpful? Give feedback.
-
Hi, is there a solution for this that works with react-query |
Beta Was this translation helpful? Give feedback.
-
Full support!This next approach makes no sense, in my opinion. I'm building a fullstack app, using services and repositories to achieve a well-defined and reusable architecture. A service should return data or stop the flow if there is an error. It doesn't make sense to return objects with { error: 'error message' }. An example code, below: microcontroller.actions.ts export async function createMicrocontroller(
userId: string,
data: MicrocontrollerSchema
) {
await getMicrocontrollerService().create(userId, data);
revalidatePath("/microcontrollers");
return {
success: true,
message: "Microcontrolador criado com sucesso",
};
} microcontroller.service.ts async create(userId: string, data: MicrocontrollerSchema) {
const user = await this.userRepository.findById(userId);
if (!user) {
throw new NotFoundError("Usuário não encontrado");
}
const macAddressExists =
await this.microcontrollerRepository.findByMacAddress(data.macAddress);
if (macAddressExists) {
throw new ConflictError(
"Já existe um microcontrolador com esse MAC Address"
);
}
const plateExists = await this.microcontrollerRepository.findByPlate(
data.plate
);
if (plateExists) {
throw new ConflictError("Já existe um microcontrolador com essa placa");
}
return this.microcontrollerRepository.create({
id: "",
userId,
...data,
});
} In my frontend the data presented are simply the error messages. A classic and simple structure to avoid many try-catch blocks that become polluting. An alternative I tried to use is to use a handler function that would have the try-catch and map the error (HttpError is just a custom error class that inherits from Error, but requires an parameter called statusCode): export function error_handler(callback: (...params: any[]) => any) {
try {
return await callback();
} catch (error) {
if (error instanceof ZodError) {
return NextResponse.json(
{
message: "Validation error",
errors: error.errors.map((e) => e.message),
},
{ status: 422 }
);
}
return NextResponse.json(
{
message:
error instanceof HttpError || error instanceof Error
? error.message
: "Internal Server Error",
},
{ status: error instanceof HttpError ? error.statusCode : 500 }
);
}
} so microcontroller.actions.ts would be: export const createMicrocontroller = error_handler(async (
userId: string,
data: MicrocontrollerSchema
) => {
await getMicrocontrollerService().create(userId, data);
revalidatePath("/microcontrollers");
return {
success: true,
message: "Microcontrolador criado com sucesso",
};
}) But that doesn't work Perhaps a solution would be to invert the direction of the error handler. export async function createMicrocontroller(
userId: string,
data: MicrocontrollerSchema
) {
return error_handler(async () => {
await getMicrocontrollerService().create(userId, data);
revalidatePath("/microcontrollers");
return {
success: true,
message: "Microcontrolador criado com sucesso",
};
});
} I have done a few tests, and so far it has not worked either, but in this case I believe I am overlooking some detail about the project structure and where would be the correct place to put the try-catch. Even if it works, in the end the solution becomes very verbose. If there were a way to simply disable this handling that next does, it would solve the whole problem. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
There's a major flaw in how errors for server actions are handled. They work differently in dev and in prod.
In dev: throwing an error in a server action exposes the error that occurred.
In prod: the message isn't exposed to the client. Instead you see: "An error occurred in the Server Components render"
The Next.js team's reasoning for this design choice is to make it easier for devs to see errors when working on their app.
The problem is that it actually makes it harder, because you only notice errors come up when running in production, and not immediately in development.
This has happened to my users. This has happened to me as a user on other sites too. Even well funded dev teams are making this mistake.
The fix:
Make prod and dev consistent. Or at the very least, add a message to the start of the error message that is exposed to the client that this will only show in dev. eg. "This only shows in Next.js development. You should not use this field in production. Error: ..."
Beta Was this translation helpful? Give feedback.
All reactions