From 84a309d669f69ca7c9a43e997fc694d192459f31 Mon Sep 17 00:00:00 2001
From: David Luzar <5153846+dwelle@users.noreply.github.com>
Date: Wed, 21 Jan 2026 14:07:23 +0100
Subject: [PATCH] fix: ttd 429 error handling (#10680)
---
.../components/TTDDialog/TTDDialogOutput.tsx | 4 +-
.../TTDDialog/hooks/useTextGeneration.ts | 128 +++++++-----------
packages/excalidraw/locales/en.json | 6 +-
3 files changed, 57 insertions(+), 81 deletions(-)
diff --git a/packages/excalidraw/components/TTDDialog/TTDDialogOutput.tsx b/packages/excalidraw/components/TTDDialog/TTDDialogOutput.tsx
index f19d459633..443ccc4d3e 100644
--- a/packages/excalidraw/components/TTDDialog/TTDDialogOutput.tsx
+++ b/packages/excalidraw/components/TTDDialog/TTDDialogOutput.tsx
@@ -37,7 +37,9 @@ export const TTDDialogOutput = ({
{t("ttd.error")}
- {hideErrorDetails ? t("ttd.errorMermaidSyntax") : error.message}
+ {hideErrorDetails
+ ? t("chat.errors.mermaidParseError")
+ : error.message}
diff --git a/packages/excalidraw/components/TTDDialog/hooks/useTextGeneration.ts b/packages/excalidraw/components/TTDDialog/hooks/useTextGeneration.ts
index 47c91584e8..e31847ae0c 100644
--- a/packages/excalidraw/components/TTDDialog/hooks/useTextGeneration.ts
+++ b/packages/excalidraw/components/TTDDialog/hooks/useTextGeneration.ts
@@ -63,31 +63,6 @@ export const useTextGeneration = ({
return true;
};
- const getReadableErrorMsg = (msg: string) => {
- try {
- const content = JSON.parse(msg);
-
- const innerMessages = JSON.parse(content.message);
-
- return innerMessages
- .map((oneMsg: { message: string }) => oneMsg.message)
- .join("\n");
- } catch (err) {
- return msg;
- }
- };
-
- const handleError = (error: Error, errorType: "parse" | "network") => {
- if (errorType === "parse") {
- trackEvent("ai", "mermaid parse failed", "ttd");
- }
-
- const msg = getReadableErrorMsg(error.message);
-
- setAssistantError(msg, errorType);
- setError(error);
- };
-
const onGenerate: TTTDDialog.OnGenerate = async ({
prompt,
isRepairFlow = false,
@@ -165,6 +140,34 @@ export const useTextGeneration = ({
setRateLimits({ rateLimit, rateLimitRemaining });
}
+ if (error?.status === 429 || rateLimitRemaining === 0) {
+ setChatHistory((chatHistory) => {
+ if (error?.status === 429) {
+ chatHistory = removeLastAssistantMessage(chatHistory);
+ }
+
+ chatHistory = {
+ ...chatHistory,
+ messages: chatHistory.messages.filter(
+ (msg) =>
+ msg.type !== "warning" ||
+ msg.warningType === "rateLimitExceeded" ||
+ msg.warningType === "messageLimitExceeded",
+ ),
+ };
+ const messages = addMessages(chatHistory, [
+ {
+ type: "warning",
+ warningType:
+ rateLimitRemaining === 0
+ ? "messageLimitExceeded"
+ : "rateLimitExceeded",
+ },
+ ]);
+ return messages;
+ });
+ }
+
if (error) {
const isAborted =
error.name === "AbortError" ||
@@ -176,63 +179,34 @@ export const useTextGeneration = ({
return;
}
- if (error.status === 429) {
- setChatHistory((prev) => {
- const chatHistory = removeLastAssistantMessage(prev);
-
- return {
- ...chatHistory,
- messages: chatHistory.messages.filter(
- (msg) =>
- msg.type !== "warning" ||
- msg.warningType === "rateLimitExceeded" ||
- msg.warningType === "messageLimitExceeded",
- ),
- };
- });
-
- setChatHistory((chatHistory) => {
- return addMessages(chatHistory, [
- {
- type: "warning",
- warningType:
- rateLimitRemaining === 0
- ? "messageLimitExceeded"
- : "rateLimitExceeded",
- },
- ]);
- });
-
- return;
- } else if (rateLimitRemaining === 0) {
- setChatHistory((chatHistory) => {
- chatHistory = {
- ...chatHistory,
- messages: chatHistory.messages.filter(
- (msg) =>
- msg.type !== "warning" ||
- msg.warningType === "rateLimitExceeded" ||
- msg.warningType === "messageLimitExceeded",
- ),
- };
- return addMessages(chatHistory, [
- {
- type: "warning",
- warningType: "messageLimitExceeded",
- },
- ]);
- });
+ const _error = new Error(
+ error.message || t("chat.errors.requestFailed"),
+ );
+ if (error.status !== 429) {
+ setAssistantError(_error.message, "network");
}
+ setError(_error);
- handleError(error as Error, "network");
return;
}
- await parseMermaidToExcalidraw(generatedResponse ?? "");
-
- trackEvent("ai", "mermaid parse success", "ttd");
- } catch (error: unknown) {
- handleError(error as Error, "parse");
+ try {
+ await parseMermaidToExcalidraw(generatedResponse ?? "");
+ trackEvent("ai", "mermaid parse success", "ttd");
+ } catch (error: any) {
+ trackEvent("ai", "mermaid parse failed", "ttd");
+ const _error = new Error(
+ error.message || t("chat.errors.mermaidParseError"),
+ );
+ setAssistantError(_error.message, "parse");
+ setError(_error);
+ }
+ } catch (error: any) {
+ const _error = new Error(
+ error.message || t("chat.errors.generationFailed"),
+ );
+ setAssistantError(_error.message, "other");
+ setError(_error);
} finally {
streamingAbortControllerRef.current = null;
}
diff --git a/packages/excalidraw/locales/en.json b/packages/excalidraw/locales/en.json
index dd69162c3f..b66485c73d 100644
--- a/packages/excalidraw/locales/en.json
+++ b/packages/excalidraw/locales/en.json
@@ -617,8 +617,7 @@
"inputPlaceholder": "Write Mermaid diagram defintion here..."
},
"ttd": {
- "error": "Error!",
- "errorMermaidSyntax": "Mermaid syntax error"
+ "error": "Error!"
},
"chat": {
"inputPlaceholder": "Start typing your diagram idea here... ({{shortcut}} for new line)",
@@ -653,7 +652,8 @@
"fixInMermaid": "Edit Mermaid manually →",
"aiRepair": "Regenerate (auto-fix) →",
"requestAborted": "Request aborted",
- "requestFailed": "Request failed"
+ "requestFailed": "Request failed",
+ "mermaidParseError": "Mermaid syntax error"
},
"rateLimit": {
"messageLimit": "You've hit your AI limit on the free plan. Try out Excalidraw+ for more or come back tomorrow.",