diff --git a/apps/web/features/editor/publish-dialog.test.ts b/apps/web/features/editor/publish-dialog.test.ts index 29176c53..d280756c 100644 --- a/apps/web/features/editor/publish-dialog.test.ts +++ b/apps/web/features/editor/publish-dialog.test.ts @@ -33,4 +33,26 @@ describe("publish error messages", () => { "The draft changed while publishing. Review the latest changes and try again.", ); }); + + test("prefers Convex error data over the client error envelope", () => { + const error = new ConvexError( + "[CONVEX M(releases:publish)] [Request ID: abc] Server Error\n Called by client", + ); + error.data = + "The draft changed while publishing. Review the latest changes and try again."; + + expect(getPublishErrorMessage(error)).toBe( + "The draft changed while publishing. Review the latest changes and try again.", + ); + }); + + test("uses the fallback for an empty Convex error envelope", () => { + expect( + getPublishErrorMessage( + new Error( + "[CONVEX M(releases:publish)] [Request ID: abc] Server Error\n Called by client", + ), + ), + ).toBe("The site could not publish"); + }); }); diff --git a/apps/web/features/editor/publish-dialog.tsx b/apps/web/features/editor/publish-dialog.tsx index 0db37a95..d4f3ad63 100644 --- a/apps/web/features/editor/publish-dialog.tsx +++ b/apps/web/features/editor/publish-dialog.tsx @@ -31,11 +31,14 @@ export function getPublishErrorMessage( error: unknown, fallback = "The site could not publish", ): string { + const dataMessage = getPublishErrorDataMessage(error); + if (dataMessage) return dataMessage; + if (error instanceof Error && error.message.trim()) { - return cleanPublishErrorMessage(error.message); + return cleanPublishErrorMessage(error.message) || fallback; } if (typeof error === "string" && error.trim()) { - return cleanPublishErrorMessage(error); + return cleanPublishErrorMessage(error) || fallback; } if ( error && @@ -44,17 +47,50 @@ export function getPublishErrorMessage( typeof error.message === "string" && error.message.trim() ) { - return cleanPublishErrorMessage(error.message); + return cleanPublishErrorMessage(error.message) || fallback; } return fallback; } +function getPublishErrorDataMessage(error: unknown): string | null { + if (!error || typeof error !== "object" || !("data" in error)) { + return null; + } + + const data = error.data; + if (typeof data === "string" && data.trim()) { + return cleanPublishErrorMessage(data) || null; + } + if ( + data && + typeof data === "object" && + "message" in data && + typeof data.message === "string" && + data.message.trim() + ) { + return cleanPublishErrorMessage(data.message) || null; + } + return null; +} + function cleanPublishErrorMessage(message: string): string { + const trimmedMessage = message.trim(); const convexErrorMarker = "Uncaught ConvexError:"; - const markerIndex = message.indexOf(convexErrorMarker); - if (markerIndex === -1) return message; + const markerIndex = trimmedMessage.indexOf(convexErrorMarker); + if (markerIndex === -1) { + if ( + /^\[CONVEX [^\]]+\([^)]*\)\](?: \[Request ID: [^\]]+\])? Server Error(?:\s+Called by client)?$/s.test( + trimmedMessage, + ) + ) { + return ""; + } + return trimmedMessage; + } - const errorMessage = message.slice(markerIndex + convexErrorMarker.length); + const errorMessage = trimmedMessage.slice( + markerIndex + convexErrorMarker.length, + ); const [userMessage = errorMessage] = errorMessage.split( /\s+at\s+[^\s(]+\s*\(/, 1,