From b1e82ba5de9ae77bb7595672c72db825db02552e Mon Sep 17 00:00:00 2001 From: Will Chen Date: Tue, 7 Oct 2025 16:37:43 -0700 Subject: [PATCH] Better spawn error message (#1434) > [!NOTE] > Structure preview errors with source-aware messaging/UI and enhance local/Docker spawn error diagnostics and logging. > > - **Frontend**: > - **Error model**: Change `previewErrorMessageAtom` from `string` to `{ message, source }` to distinguish `preview-app` vs `dyad-app` errors. > - **Preview UI**: Update `ErrorBanner` in `components/preview_panel/PreviewIframe.tsx` to use `error.message`, show an "Internal Dyad error" chip for `dyad-app`, conditional tip text, and hide AI fix for non-`preview-app` errors; use `cn` helper. > - **Error propagation**: Wrap iframe and build errors via `setErrorMessage({ message, source: "preview-app" })`; adjust AI prompt to use `errorMessage.message`. > - **Hooks**: > - `useRunApp`: On run/stop/restart failures, set `{ message, source: "dyad-app" }` in `previewErrorMessageAtom`. > - **Backend**: > - `ipc/handlers/app_handlers.ts`: Improve spawn failure handling for local node and Docker: capture stderr as strings, collect error details (`message`, `code`, `errno`, `syscall`, `path`, `spawnargs`), log with context, and throw enriched error messages. > > Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 4135b04e19431dd53848c3266e5211e4c9df6aa2. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot). --------- Co-authored-by: graphite-app[bot] <96075541+graphite-app[bot]@users.noreply.github.com> --- src/atoms/appAtoms.ts | 4 +- .../preview_panel/PreviewIframe.tsx | 37 ++++++--- src/hooks/useRunApp.ts | 21 ++++- src/ipc/handlers/app_handlers.ts | 78 ++++++++++++++++--- 4 files changed, 115 insertions(+), 25 deletions(-) diff --git a/src/atoms/appAtoms.ts b/src/atoms/appAtoms.ts index c4d20ba..9a692b8 100644 --- a/src/atoms/appAtoms.ts +++ b/src/atoms/appAtoms.ts @@ -23,4 +23,6 @@ export const envVarsAtom = atom>({}); export const previewPanelKeyAtom = atom(0); -export const previewErrorMessageAtom = atom(undefined); +export const previewErrorMessageAtom = atom< + { message: string; source: "preview-app" | "dyad-app" } | undefined +>(undefined); diff --git a/src/components/preview_panel/PreviewIframe.tsx b/src/components/preview_panel/PreviewIframe.tsx index 90ecbff..37bb350 100644 --- a/src/components/preview_panel/PreviewIframe.tsx +++ b/src/components/preview_panel/PreviewIframe.tsx @@ -41,9 +41,10 @@ import { } from "@/components/ui/tooltip"; import { useRunApp } from "@/hooks/useRunApp"; import { useShortcut } from "@/hooks/useShortcut"; +import { cn } from "@/lib/utils"; interface ErrorBannerProps { - error: string | undefined; + error: { message: string; source: "preview-app" | "dyad-app" } | undefined; onDismiss: () => void; onAIFix: () => void; } @@ -52,12 +53,12 @@ const ErrorBanner = ({ error, onDismiss, onAIFix }: ErrorBannerProps) => { const [isCollapsed, setIsCollapsed] = useState(true); const { isStreaming } = useStreamChat(); if (!error) return null; - const isDockerError = error.includes("Cannot connect to the Docker"); + const isDockerError = error.message.includes("Cannot connect to the Docker"); const getTruncatedError = () => { - const firstLine = error.split("\n")[0]; + const firstLine = error.message.split("\n")[0]; const snippetLength = 250; - const snippet = error.substring(0, snippetLength); + const snippet = error.message.substring(0, snippetLength); return firstLine.length < snippet.length ? firstLine : snippet + (snippet.length === snippetLength ? "..." : ""); @@ -76,8 +77,20 @@ const ErrorBanner = ({ error, onDismiss, onAIFix }: ErrorBannerProps) => { + {/* Add a little chip that says "Internal error" if source is "dyad-app" */} + {error.source === "dyad-app" && ( +
+ Internal Dyad error +
+ )} + {/* Error message in the middle */} -
+
setIsCollapsed(!isCollapsed)} @@ -88,7 +101,7 @@ const ErrorBanner = ({ error, onDismiss, onAIFix }: ErrorBannerProps) => { isCollapsed ? "" : "rotate-90" }`} /> - {isCollapsed ? getTruncatedError() : error} + {isCollapsed ? getTruncatedError() : error.message}
@@ -102,13 +115,15 @@ const ErrorBanner = ({ error, onDismiss, onAIFix }: ErrorBannerProps) => { Tip: {isDockerError ? "Make sure Docker Desktop is running and try restarting the app." - : "Check if restarting the app fixes the error."} + : error.source === "dyad-app" + ? "Try restarting the Dyad app or restarting your computer to see if that fixes the error." + : "Check if restarting the app fixes the error."}
{/* AI Fix button at the bottom */} - {!isDockerError && ( + {!isDockerError && error.source === "preview-app" && (