diff --git a/ui/desktop/src/components/ErrorBoundary.tsx b/ui/desktop/src/components/ErrorBoundary.tsx
index 4784024502f0..8163b5fb0cff 100644
--- a/ui/desktop/src/components/ErrorBoundary.tsx
+++ b/ui/desktop/src/components/ErrorBoundary.tsx
@@ -1,7 +1,7 @@
import React from 'react';
import { Button } from './ui/button';
import { AlertTriangle } from 'lucide-react';
-import { errorMessage } from '../utils/conversionUtils';
+import { errorMessage, formatErrorForLogging } from '../utils/conversionUtils';
import { trackErrorWithContext, trackEvent, getErrorType } from '../utils/analytics';
function getCurrentPage(): string {
@@ -10,7 +10,8 @@ function getCurrentPage(): string {
// Capture unhandled promise rejections
window.addEventListener('unhandledrejection', (event) => {
- window.electron.logInfo(`[UNHANDLED REJECTION] ${event.reason}`);
+ const reasonStr = formatErrorForLogging(event.reason);
+ window.electron.logInfo(`[UNHANDLED REJECTION] ${reasonStr}`);
trackErrorWithContext(event.reason, {
component: 'global',
page: getCurrentPage(),
diff --git a/ui/desktop/src/components/settings/chat/GoosehintsModal.tsx b/ui/desktop/src/components/settings/chat/GoosehintsModal.tsx
index e74c20adb39c..b4e925c930b5 100644
--- a/ui/desktop/src/components/settings/chat/GoosehintsModal.tsx
+++ b/ui/desktop/src/components/settings/chat/GoosehintsModal.tsx
@@ -9,6 +9,7 @@ import {
DialogHeader,
DialogTitle,
} from '../../ui/dialog';
+import { errorMessage } from '../../../utils/conversionUtils';
const HelpText = () => (
@@ -39,7 +40,7 @@ const HelpText = () => (
const ErrorDisplay = ({ error }: { error: Error }) => (
-
Error reading .goosehints file: {JSON.stringify(error)}
+
Error reading .goosehints file: {errorMessage(error)}
);
diff --git a/ui/desktop/src/components/settings/providers/modal/ProviderConfiguationModal.tsx b/ui/desktop/src/components/settings/providers/modal/ProviderConfiguationModal.tsx
index 24a49151e7b4..688d86cfc767 100644
--- a/ui/desktop/src/components/settings/providers/modal/ProviderConfiguationModal.tsx
+++ b/ui/desktop/src/components/settings/providers/modal/ProviderConfiguationModal.tsx
@@ -19,20 +19,7 @@ import { useModelAndProvider } from '../../../ModelAndProviderContext';
import { AlertTriangle, LogIn } from 'lucide-react';
import { ProviderDetails, removeCustomProvider, configureProviderOauth } from '../../../../api';
import { Button } from '../../../../components/ui/button';
-
-const formatErrorMessage = (error: unknown): string => {
- if (error instanceof Error) {
- return error.message;
- }
- if (typeof error === 'string') {
- return error;
- }
- try {
- return JSON.stringify(error);
- } catch {
- return String(error);
- }
-};
+import { errorMessage } from '../../../../utils/conversionUtils';
interface ProviderConfigurationModalProps {
provider: ProviderDetails;
@@ -87,7 +74,7 @@ export default function ProviderConfigurationModal({
onClose();
}
} catch (err) {
- setError(`OAuth login failed: ${formatErrorMessage(err)}`);
+ setError(`OAuth login failed: ${errorMessage(err)}`);
} finally {
setIsOAuthLoading(false);
}
@@ -130,7 +117,7 @@ export default function ProviderConfigurationModal({
onClose();
}
} catch (error) {
- setError(formatErrorMessage(error));
+ setError(errorMessage(error));
}
};
diff --git a/ui/desktop/src/main.ts b/ui/desktop/src/main.ts
index 897430f68154..62dac2ae2ba9 100644
--- a/ui/desktop/src/main.ts
+++ b/ui/desktop/src/main.ts
@@ -28,7 +28,7 @@ import { expandTilde } from './utils/pathUtils';
import log from './utils/logger';
import { ensureWinShims } from './utils/winShims';
import { addRecentDir, loadRecentDirs } from './utils/recentDirs';
-import { formatAppName, errorMessage } from './utils/conversionUtils';
+import { formatAppName, errorMessage, formatErrorForLogging } from './utils/conversionUtils';
import type { Settings } from './utils/settings';
import { defaultKeyboardShortcuts, getKeyboardShortcuts } from './utils/settings';
import * as crypto from 'crypto';
@@ -1116,12 +1116,12 @@ const handleFatalError = (error: Error) => {
};
process.on('uncaughtException', (error) => {
- console.error('Uncaught Exception:', error);
+ console.error('Uncaught Exception:', formatErrorForLogging(error));
handleFatalError(error);
});
process.on('unhandledRejection', (error) => {
- console.error('Unhandled Rejection:', error);
+ console.error('Unhandled Rejection:', formatErrorForLogging(error));
handleFatalError(error instanceof Error ? error : new Error(String(error)));
});
diff --git a/ui/desktop/src/utils/analytics.ts b/ui/desktop/src/utils/analytics.ts
index 91794b5d9ef2..73ee208f4cfe 100644
--- a/ui/desktop/src/utils/analytics.ts
+++ b/ui/desktop/src/utils/analytics.ts
@@ -241,10 +241,10 @@ export function trackPageView(page: string, referrer?: string): void {
export function trackError(
errorType: string,
options: {
- component?: string; // React component name
- page?: string; // Current route/page
- action?: string; // What user was doing
- stackSummary?: string; // Use getStackSummary() to generate
+ component?: string;
+ page?: string;
+ action?: string;
+ stackSummary?: string;
recoverable?: boolean;
} = {}
): void {
diff --git a/ui/desktop/src/utils/conversionUtils.ts b/ui/desktop/src/utils/conversionUtils.ts
index 4e6a2fce8a5f..b509ac33b114 100644
--- a/ui/desktop/src/utils/conversionUtils.ts
+++ b/ui/desktop/src/utils/conversionUtils.ts
@@ -22,6 +22,20 @@ export function errorMessage(err: Error | unknown, default_value?: string) {
}
}
+export function formatErrorForLogging(error: unknown): string {
+ if (error instanceof Error) {
+ return `${error.name}: ${error.message}${error.stack ? `\n${error.stack}` : ''}`;
+ }
+ if (typeof error === 'object' && error !== null) {
+ try {
+ return JSON.stringify(error, null, 2);
+ } catch {
+ return String(error);
+ }
+ }
+ return String(error);
+}
+
export async function compressImageDataUrl(dataUrl: string): Promise
{
return new Promise((resolve, reject) => {
const img = new globalThis.Image();