Describe the bug
When a file can't be shown in the artifact preview panel because it was moved, renamed, or deleted, the panel shows the raw Node.js filesystem error verbatim, e.g.:
ENOENT: no such file or directory, stat '/Users/wanjun/Desktop/normal_numbers_ggplot_sorted.png'
This is too blunt/technical. It should be a human-readable message that explains what happened — e.g. "This file was moved or deleted, so it can't be previewed."
Root cause (traced in code)
The artifact preview reads the file in the Electron main process and passes the raw error message straight through to the UI:
ui/desktop/src/main.ts → read-artifact-file handler: const stats = await fs.stat(resolvedPath) (~L2542) throws an ENOENT error when the file no longer exists.
- Same handler's catch block (~L2632–2640):
} catch (error) {
const message = error instanceof Error ? error.message : 'Could not read artifact file';
return { kind: 'error', title, path: resolvedPath, error: message, found: false };
}
error.message is the raw Node string ENOENT: no such file or directory, stat '<path>'.
ui/desktop/src/components/artifacts/ArtifactViewer.tsx (~L907–908) renders it verbatim:
if (file.kind === 'error') {
return <div className="p-4 text-sm text-text-muted">{file.error}</div>;
}
So the exact errno/syscall string the user pasted comes from fs.stat failing and the message being forwarded unmodified.
Suggested fix
Map common error.codes to friendly messages in the read-artifact-file catch block (it has access to error.code), and keep the raw detail out of the primary line (the file path/title is already returned separately, so the message doesn't need to embed the path):
ENOENT → "This file was moved, renamed, or deleted, so it can't be previewed anymore."
EACCES / EPERM → "Biorouter doesn't have permission to read this file."
EISDIR / ENOTDIR → a suitable variant.
- Anything else → the existing generic "Could not read artifact file."
Optionally return a structured { code } alongside error so the viewer can pick an icon/wording, and (nice-to-have) render a "moved or deleted" empty-state in ArtifactViewer.tsx rather than a plain gray line.
Note: the sibling read-file handler (main.ts ~L2511) already special-cases ENOENT (it doesn't even console.error on it), so treating a missing file as an expected, friendly state — not a raw error — is consistent with existing behavior.
Steps to reproduce
- Have the agent create a file artifact (e.g. a
.png plot) so it opens in the preview panel.
- Move or delete that file on disk (or rename it).
- Reopen/refresh the artifact in the panel.
Expected: a friendly "this file was moved or deleted" message.
Actual: ENOENT: no such file or directory, stat '<path>'.
Describe the bug
When a file can't be shown in the artifact preview panel because it was moved, renamed, or deleted, the panel shows the raw Node.js filesystem error verbatim, e.g.:
This is too blunt/technical. It should be a human-readable message that explains what happened — e.g. "This file was moved or deleted, so it can't be previewed."
Root cause (traced in code)
The artifact preview reads the file in the Electron main process and passes the raw error message straight through to the UI:
ui/desktop/src/main.ts→read-artifact-filehandler:const stats = await fs.stat(resolvedPath)(~L2542) throws anENOENTerror when the file no longer exists.error.messageis the raw Node stringENOENT: no such file or directory, stat '<path>'.ui/desktop/src/components/artifacts/ArtifactViewer.tsx(~L907–908) renders it verbatim:So the exact
errno/syscallstring the user pasted comes fromfs.statfailing and the message being forwarded unmodified.Suggested fix
Map common
error.codes to friendly messages in theread-artifact-filecatch block (it has access toerror.code), and keep the raw detail out of the primary line (the filepath/titleis already returned separately, so the message doesn't need to embed the path):ENOENT→ "This file was moved, renamed, or deleted, so it can't be previewed anymore."EACCES/EPERM→ "Biorouter doesn't have permission to read this file."EISDIR/ENOTDIR→ a suitable variant.Optionally return a structured
{ code }alongsideerrorso the viewer can pick an icon/wording, and (nice-to-have) render a "moved or deleted" empty-state inArtifactViewer.tsxrather than a plain gray line.Note: the sibling
read-filehandler (main.ts~L2511) already special-casesENOENT(it doesn't evenconsole.erroron it), so treating a missing file as an expected, friendly state — not a raw error — is consistent with existing behavior.Steps to reproduce
.pngplot) so it opens in the preview panel.Expected: a friendly "this file was moved or deleted" message.
Actual:
ENOENT: no such file or directory, stat '<path>'.