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();