Error Handling
The backend utilizes a structured error handling pattern to ensure errors survive the Convex network boundary and arrive at the client with useful metadata.
The backend utilizes a structured error handling pattern to ensure errors survive the Convex network boundary and arrive at the client with useful metadata.
The Problem
By default, if a Convex function throws an Error("Something went wrong"),
Convex redacts the message in production for security reasons. The client sees a
generic "ConvexError".
The Solution
The starter uses ConvexError to pass a structured payload to the client. The
base structure is defined in packages/backend/convex/errors.ts.
Error Factories
Never throw new Error(). Instead, import an error factory:
import { notFound, forbidden, invalidInput, conflict } from "../errors";
// 404 Not Found equivalent
throw notFound("The requested record does not exist.");
// 403 Forbidden equivalent
throw forbidden("Only owners can delete organizations.");
// 400 Bad Request equivalent
throw invalidInput("Workspace name must be alphanumeric.");
// 409 Conflict equivalent
throw conflict("That user is already a member.");Catching on the Client
When these errors are thrown, the Convex React client catches them. You can inspect the payload:
import { useMutation } from "convex/react";
import { ConvexError } from "convex/values";
import { toast } from "sonner";
function Form() {
const submit = useMutation(api.example.mutation);
const handleSubmit = async () => {
try {
await submit();
} catch (error) {
if (error instanceof ConvexError) {
// error.data is the structured payload
const { code, message } = error.data;
toast.error(`${code}: ${message}`);
} else {
toast.error("An unexpected error occurred.");
}
}
};
}Internal Errors
If a function throws an unhandled exception (e.g. TypeError, ReferenceError,
or a generic Error thrown by a third-party library), Convex will redact it
in production.
This is correct behavior: you don't want internal stack traces or library errors
leaking to the client. Only throw the factory errors (notFound, conflict,
etc.) for intentional, client-facing failure states.