Better spawn error message (#1434)
<!-- CURSOR_SUMMARY -->
> [!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.
>
> <sup>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).</sup>
<!-- /CURSOR_SUMMARY -->
---------
Co-authored-by: graphite-app[bot] <96075541+graphite-app[bot]@users.noreply.github.com>
This commit is contained in:
@@ -152,13 +152,44 @@ async function executeAppLocalNode({
|
||||
if (!spawnedProcess.pid) {
|
||||
// Attempt to capture any immediate errors if possible
|
||||
let errorOutput = "";
|
||||
spawnedProcess.stderr?.on("data", (data) => (errorOutput += data));
|
||||
await new Promise((resolve) => spawnedProcess.on("error", resolve)); // Wait for error event
|
||||
throw new Error(
|
||||
`Failed to spawn process for app ${appId}. Error: ${
|
||||
errorOutput || "Unknown spawn error"
|
||||
let spawnErr: any | null = null;
|
||||
spawnedProcess.stderr?.on(
|
||||
"data",
|
||||
(data) => (errorOutput += data.toString()),
|
||||
);
|
||||
await new Promise<void>((resolve) => {
|
||||
spawnedProcess.once("error", (err) => {
|
||||
spawnErr = err;
|
||||
resolve();
|
||||
});
|
||||
}); // Wait for error event
|
||||
|
||||
const details = [
|
||||
spawnErr?.message ? `message=${spawnErr.message}` : null,
|
||||
spawnErr?.code ? `code=${spawnErr.code}` : null,
|
||||
spawnErr?.errno ? `errno=${spawnErr.errno}` : null,
|
||||
spawnErr?.syscall ? `syscall=${spawnErr.syscall}` : null,
|
||||
spawnErr?.path ? `path=${spawnErr.path}` : null,
|
||||
spawnErr?.spawnargs
|
||||
? `spawnargs=${JSON.stringify(spawnErr.spawnargs)}`
|
||||
: null,
|
||||
]
|
||||
.filter(Boolean)
|
||||
.join(", ");
|
||||
|
||||
logger.error(
|
||||
`Failed to spawn process for app ${appId}. Command="${command}", CWD="${appPath}", ${details}\nSTDERR:\n${
|
||||
errorOutput || "(empty)"
|
||||
}`,
|
||||
);
|
||||
|
||||
throw new Error(
|
||||
`Failed to spawn process for app ${appId}.
|
||||
Error output:
|
||||
${errorOutput || "(empty)"}
|
||||
Details: ${details || "n/a"}
|
||||
`,
|
||||
);
|
||||
}
|
||||
|
||||
// Increment the counter and store the process reference with its ID
|
||||
@@ -409,13 +440,40 @@ RUN npm install -g pnpm
|
||||
if (!process.pid) {
|
||||
// Attempt to capture any immediate errors if possible
|
||||
let errorOutput = "";
|
||||
process.stderr?.on("data", (data) => (errorOutput += data));
|
||||
await new Promise((resolve) => process.on("error", resolve)); // Wait for error event
|
||||
throw new Error(
|
||||
`Failed to spawn Docker container for app ${appId}. Error: ${
|
||||
errorOutput || "Unknown spawn error"
|
||||
let spawnErr: any = null;
|
||||
process.stderr?.on("data", (data) => (errorOutput += data.toString()));
|
||||
await new Promise<void>((resolve) => {
|
||||
process.once("error", (err) => {
|
||||
spawnErr = err;
|
||||
resolve();
|
||||
});
|
||||
}); // Wait for error event
|
||||
|
||||
const details = [
|
||||
spawnErr?.message ? `message=${spawnErr.message}` : null,
|
||||
spawnErr?.code ? `code=${spawnErr.code}` : null,
|
||||
spawnErr?.errno ? `errno=${spawnErr.errno}` : null,
|
||||
spawnErr?.syscall ? `syscall=${spawnErr.syscall}` : null,
|
||||
spawnErr?.path ? `path=${spawnErr.path}` : null,
|
||||
spawnErr?.spawnargs
|
||||
? `spawnargs=${JSON.stringify(spawnErr.spawnargs)}`
|
||||
: null,
|
||||
]
|
||||
.filter(Boolean)
|
||||
.join(", ");
|
||||
|
||||
logger.error(
|
||||
`Failed to spawn Docker container for app ${appId}. ${details}\nSTDERR:\n${
|
||||
errorOutput || "(empty)"
|
||||
}`,
|
||||
);
|
||||
|
||||
throw new Error(
|
||||
`Failed to spawn Docker container for app ${appId}.
|
||||
Details: ${details || "n/a"}
|
||||
STDERR:
|
||||
${errorOutput || "(empty)"}`,
|
||||
);
|
||||
}
|
||||
|
||||
// Increment the counter and store the process reference with its ID
|
||||
|
||||
Reference in New Issue
Block a user