different-ai/openwork · error
Cannot save non-file artifact.
Error message
Cannot save non-file artifact.
What it means
The artifact save mutation in ArtifactPanelView only supports artifacts whose target is a file (path-backed). If the selected artifact's target.kind is not 'file' (e.g. a terminal/buffer or other in-memory target), there is no workspace file path to write to, so the mutation throws before calling client.writeWorkspaceFile.
Source
Thrown at apps/app/src/react-app/domains/session/artifacts/artifact-panel.tsx:184
useEffect(() => {
setEditing(false);
setDraft("");
lastSyncedRef.current = null;
failedDraftRef.current = null;
}, [target.id, workspaceId]);
useEffect(() => {
if (data?.kind === "text" && data.data !== lastSyncedRef.current) {
lastSyncedRef.current = data.data;
setDraft(data.data);
}
}, [data]);
const { mutate, mutateAsync, isPending: isSaving } = useMutation({
mutationFn: async (input: SaveArtifactInput) => {
if (target.kind !== "file") {
throw new Error("Cannot save non-file artifact.");
}
if (input.kind === "text") {
return client.writeWorkspaceFile(workspaceId, { path: target.value, content: input.data, baseUpdatedAt: input.baseUpdatedAt });
}
return client.writeWorkspaceBinaryFile(workspaceId, { path: target.value, data: input.data, baseUpdatedAt: input.baseUpdatedAt });
},
onSuccess: (result, input) => {
queryClient.setQueryData<ArtifactQueryState>(
["artifact-panel", workspaceId, target.id, target.updatedAt ?? null] as const,
input.kind === "text"
? { kind: "text", data: input.data, updatedAt: result.updatedAt ?? null }
: { kind: "binary", data: input.data, contentType: data?.kind === "binary" ? data.contentType : null, updatedAt: result.updatedAt ?? null },
);
if (input.kind === "text") {
lastSyncedRef.current = input.data;View on GitHub (pinned to 2b7df46e8a)
Solutions
- Only render/enable the Save button when target.kind === "file"
- Before mutating, check target.kind and route non-file targets to a different save path or show a disabled state
- If the artifact should be file-backed, ensure the target is resolved to a workspace file path before opening the panel
- Catch the error in an onError handler and surface a clear 'this artifact type cannot be saved' message
Example fix
// before
await mutateAsync({ kind: "text", data, baseUpdatedAt });
// after
if (target.kind !== "file") {
toast.error("Only file artifacts can be saved to the workspace.");
return;
}
await mutateAsync({ kind: "text", data, baseUpdatedAt }); Defensive patterns
Strategy: validation
Validate before calling
if (target.kind !== "file") {
toast.error("Only file artifacts can be saved to the workspace.");
return;
} Type guard
const isFileTarget = (t: Target): t is Extract<Target, { kind: "file" }> => t.kind === "file"; Try / catch
try {
await mutateAsync(input);
} catch (e) {
if (e instanceof Error && e.message === "Cannot save non-file artifact.") {
toast.error("This artifact type cannot be saved as a file.");
} else throw e;
} Prevention
- Gate the Save button on target.kind === "file"
- Type-narrow target with a discriminated union before the mutation
- Resolve artifacts to file-backed targets when opening the panel
- Add an onError handler on the mutation to surface friendly messages
When it happens
Trigger: Clicking Save in the artifact panel while the panel's `target.kind` is anything other than "file"; calling the mutation with a SaveArtifactInput whose underlying target is a non-file artifact (e.g. text captured from a tool output rather than a workspace file).
Common situations: Users open an artifact derived from a chat/tool response or a virtual buffer and hit Save expecting it to persist; a target computed from stale or wrong panel state; UI allowing Save on artifact types it cannot persist.
Related errors
- URLs open in browser tabs.
- File not found in this workspace.
- settings.environment.apply_blocked_active_tasks
- settings.environment.apply_no_local_workspace
- app.error_connect_first
AI-assisted analysis of different-ai/openwork@2b7df46e8a (2026-09-01).
Data as JSON: /api/errors/2f289075c98c9868.
Report an issue: GitHub.