From 5f5a78a044cbdd00aaef0c025d47f9746a956735 Mon Sep 17 00:00:00 2001 From: zipg Date: Thu, 17 Sep 2026 01:38:13 +0800 Subject: [PATCH] fix(grid): show real save error message instead of [object Object] --- apps/desktop/src/lib/backend/errorUtils.ts | 6 ++-- .../dataGrid/__tests__/dataGridSql.spec.ts | 35 +++++++++++++++++++ apps/desktop/src/lib/dataGrid/dataGridSql.ts | 10 +++++- 3 files changed, 48 insertions(+), 3 deletions(-) create mode 100644 apps/desktop/src/lib/dataGrid/__tests__/dataGridSql.spec.ts diff --git a/apps/desktop/src/lib/backend/errorUtils.ts b/apps/desktop/src/lib/backend/errorUtils.ts index 657940dc8b..4e614a8ded 100644 --- a/apps/desktop/src/lib/backend/errorUtils.ts +++ b/apps/desktop/src/lib/backend/errorUtils.ts @@ -283,9 +283,11 @@ export function formatError(e: unknown): string { } } - // Fallback: attempt to stringify + // Fallback: prefer bounded nested text (message/reason/detail, .error/.backendError) + // over raw string coercion so object-shaped failures never degrade to "[object Object]". + const fallback = boundedFallbackText(e); try { - return sanitizeBackendErrorMessage(String(e)); + return sanitizeBackendErrorMessage(fallback ?? String(e)); } catch { return "Unknown error occurred"; } diff --git a/apps/desktop/src/lib/dataGrid/__tests__/dataGridSql.spec.ts b/apps/desktop/src/lib/dataGrid/__tests__/dataGridSql.spec.ts new file mode 100644 index 0000000000..3853939865 --- /dev/null +++ b/apps/desktop/src/lib/dataGrid/__tests__/dataGridSql.spec.ts @@ -0,0 +1,35 @@ +import { describe, expect, it } from "vitest"; +import { normalizeDataGridSaveError } from "@/lib/dataGrid/dataGridSql"; + +describe("normalizeDataGridSaveError", () => { + it("extracts a message from an object-shaped save failure", () => { + expect(normalizeDataGridSaveError("mysql", { message: "Duplicate entry for key id" })).toBe("Duplicate entry for key id"); + }); + + it("extracts messages from nested backend request errors", () => { + expect(normalizeDataGridSaveError("mysql", { error: { message: "Column count does not match" } })).toBe("Column count does not match"); + }); + + it("keeps Error messages and database-specific guidance intact", () => { + expect(normalizeDataGridSaveError("mysql", new Error("save failed"))).toBe("save failed"); + expect(normalizeDataGridSaveError("hive", new Error("Error 10294: update is disabled"))).toContain("Hive UPDATE/DELETE"); + }); + + it("prefers the Error message over a backend envelope without detail", () => { + const sqlError = Object.assign(new Error("Duplicate entry '1' for key 'PRIMARY'"), { + backendError: { + version: 1, + code: "DBX-JDBC-4001", + messageKey: "backendErrors.jdbc.sqlFailed", + messageParams: { stage: "execute" }, + source: "jdbc_agent", + operationOutcome: "unknown", + }, + }); + expect(normalizeDataGridSaveError("mysql", sqlError)).toBe("Duplicate entry '1' for key 'PRIMARY'"); + }); + + it("extracts messages from nested backendError envelopes", () => { + expect(normalizeDataGridSaveError("mysql", { backendError: { message: "Connection refused" } })).toBe("Connection refused"); + }); +}); diff --git a/apps/desktop/src/lib/dataGrid/dataGridSql.ts b/apps/desktop/src/lib/dataGrid/dataGridSql.ts index 23d2e47695..a433025929 100644 --- a/apps/desktop/src/lib/dataGrid/dataGridSql.ts +++ b/apps/desktop/src/lib/dataGrid/dataGridSql.ts @@ -1,5 +1,6 @@ import type { DatabaseType } from "@/types/database"; import * as api from "@/lib/backend/api"; +import { formatError } from "@/lib/backend/errorUtils"; export type GridCellValue = string | number | boolean | null | unknown[] | { [key: string]: unknown }; @@ -167,8 +168,15 @@ export function buildHiveTablePropertiesSql(options: HiveTablePropertiesSqlOptio return api.buildHiveTablePropertiesSql(options); } +function formatDataGridSaveError(error: unknown): string { + if (error instanceof Error && error.message) { + return error.message; + } + return formatError(error); +} + export function normalizeDataGridSaveError(databaseType: DatabaseType | undefined, error: unknown): string { - const message = error instanceof Error ? error.message : String(error); + const message = formatDataGridSaveError(error); if ((databaseType === "hive" || databaseType === "argo") && /Attempt to do update or delete|Error 10294/i.test(message)) { return "Hive UPDATE/DELETE are not enabled for this table or server. Add rows with INSERT, or enable ACID transactional tables in Hive before editing/deleting existing rows."; }