From e545fa219499f28a3e45a9a5b5fdad6bb3d8d70d Mon Sep 17 00:00:00 2001 From: Felix <24791380+vcfgv@users.noreply.github.com> Date: Thu, 30 Apr 2026 18:33:03 +0800 Subject: [PATCH] fix: improve error handling by returning specific error messages in skill routes and IPC handlers (#945) --- electron/api/routes/skills.ts | 18 +++++++++--------- electron/main/ipc-handlers.ts | 8 ++++---- src/pages/Skills/index.tsx | 2 +- src/stores/skills.ts | 13 ++++++++----- 4 files changed, 22 insertions(+), 19 deletions(-) diff --git a/electron/api/routes/skills.ts b/electron/api/routes/skills.ts index 21f5c6c..49559d1 100644 --- a/electron/api/routes/skills.ts +++ b/electron/api/routes/skills.ts @@ -28,7 +28,7 @@ export async function handleSkillRoutes( env: body.env, })); } catch (error) { - sendJson(res, 500, { success: false, error: String(error) }); + sendJson(res, 500, { success: false, error: error instanceof Error ? error.message : String(error) }); } return true; } @@ -58,7 +58,7 @@ export async function handleSkillRoutes( skills: filterEnabledQuickAccessSkills(scannedSkills, runtimeSkills, configs), }); } catch (error) { - sendJson(res, 500, { success: false, error: String(error) }); + sendJson(res, 500, { success: false, error: error instanceof Error ? error.message : String(error) }); } return true; } @@ -70,7 +70,7 @@ export async function handleSkillRoutes( capability: await ctx.clawHubService.getMarketplaceCapability(), }); } catch (error) { - sendJson(res, 500, { success: false, error: String(error) }); + sendJson(res, 500, { success: false, error: error instanceof Error ? error.message : String(error) }); } return true; } @@ -83,7 +83,7 @@ export async function handleSkillRoutes( results: await ctx.clawHubService.search(body), }); } catch (error) { - sendJson(res, 500, { success: false, error: String(error) }); + sendJson(res, 500, { success: false, error: error instanceof Error ? error.message : String(error) }); } return true; } @@ -94,7 +94,7 @@ export async function handleSkillRoutes( await ctx.clawHubService.install(body); sendJson(res, 200, { success: true }); } catch (error) { - sendJson(res, 500, { success: false, error: String(error) }); + sendJson(res, 500, { success: false, error: error instanceof Error ? error.message : String(error) }); } return true; } @@ -105,7 +105,7 @@ export async function handleSkillRoutes( await ctx.clawHubService.uninstall(body); sendJson(res, 200, { success: true }); } catch (error) { - sendJson(res, 500, { success: false, error: String(error) }); + sendJson(res, 500, { success: false, error: error instanceof Error ? error.message : String(error) }); } return true; } @@ -114,7 +114,7 @@ export async function handleSkillRoutes( try { sendJson(res, 200, { success: true, results: await ctx.clawHubService.listInstalled() }); } catch (error) { - sendJson(res, 500, { success: false, error: String(error) }); + sendJson(res, 500, { success: false, error: error instanceof Error ? error.message : String(error) }); } return true; } @@ -125,7 +125,7 @@ export async function handleSkillRoutes( await ctx.clawHubService.openSkillReadme(body.skillKey || body.slug || '', body.slug, body.baseDir); sendJson(res, 200, { success: true }); } catch (error) { - sendJson(res, 500, { success: false, error: String(error) }); + sendJson(res, 500, { success: false, error: error instanceof Error ? error.message : String(error) }); } return true; } @@ -136,7 +136,7 @@ export async function handleSkillRoutes( await ctx.clawHubService.openSkillPath(body.skillKey || body.slug || '', body.slug, body.baseDir); sendJson(res, 200, { success: true }); } catch (error) { - sendJson(res, 500, { success: false, error: String(error) }); + sendJson(res, 500, { success: false, error: error instanceof Error ? error.message : String(error) }); } return true; } diff --git a/electron/main/ipc-handlers.ts b/electron/main/ipc-handlers.ts index c1909e3..d50c9b1 100644 --- a/electron/main/ipc-handlers.ts +++ b/electron/main/ipc-handlers.ts @@ -2085,7 +2085,7 @@ function registerClawHubHandlers(clawHubService: ClawHubService): void { const results = await clawHubService.search(params); return { success: true, results }; } catch (error) { - return { success: false, error: String(error) }; + return { success: false, error: error instanceof Error ? error.message : String(error) }; } }); @@ -2095,7 +2095,7 @@ function registerClawHubHandlers(clawHubService: ClawHubService): void { await clawHubService.install(params); return { success: true }; } catch (error) { - return { success: false, error: String(error) }; + return { success: false, error: error instanceof Error ? error.message : String(error) }; } }); @@ -2105,7 +2105,7 @@ function registerClawHubHandlers(clawHubService: ClawHubService): void { await clawHubService.uninstall(params); return { success: true }; } catch (error) { - return { success: false, error: String(error) }; + return { success: false, error: error instanceof Error ? error.message : String(error) }; } }); @@ -2115,7 +2115,7 @@ function registerClawHubHandlers(clawHubService: ClawHubService): void { const results = await clawHubService.listInstalled(); return { success: true, results }; } catch (error) { - return { success: false, error: String(error) }; + return { success: false, error: error instanceof Error ? error.message : String(error) }; } }); diff --git a/src/pages/Skills/index.tsx b/src/pages/Skills/index.tsx index 621a79b..6072ab2 100644 --- a/src/pages/Skills/index.tsx +++ b/src/pages/Skills/index.tsx @@ -685,7 +685,7 @@ export function Skills() { {SEARCH_ERROR_CODES.has(searchError.replace('Error: ', '')) ? t(`toast.${searchError.replace('Error: ', '')}`, { path: skillsDirPath }) - : t('marketplace.searchError')} + : searchError} )} diff --git a/src/stores/skills.ts b/src/stores/skills.ts index aeac44f..a12edca 100644 --- a/src/stores/skills.ts +++ b/src/stores/skills.ts @@ -39,7 +39,7 @@ type ClawHubListResult = { function mapErrorCodeToSkillErrorKey( code: AppError['code'], operation: 'fetch' | 'search' | 'install', -): string { +): string | null { if (code === 'TIMEOUT') { return operation === 'search' ? 'searchTimeoutError' @@ -54,7 +54,7 @@ function mapErrorCodeToSkillErrorKey( ? 'installRateLimitError' : 'fetchRateLimitError'; } - return 'rateLimitError'; + return null; } interface SkillsState { @@ -172,8 +172,9 @@ export const useSkillsStore = create((set, get) => ({ } catch (error) { console.error('Failed to fetch skills:', error); const appError = normalizeAppError(error, { module: 'skills', operation: 'fetch' }); + const errorKey = mapErrorCodeToSkillErrorKey(appError.code, 'fetch'); // Preserve previous skills on error (stale-while-revalidate). - set((prev) => ({ loading: false, error: mapErrorCodeToSkillErrorKey(appError.code, 'fetch'), skills: prev.skills })); + set((prev) => ({ loading: false, error: errorKey ?? appError.message, skills: prev.skills })); } }, @@ -194,7 +195,8 @@ export const useSkillsStore = create((set, get) => ({ } } catch (error) { const appError = normalizeAppError(error, { module: 'skills', operation: 'search' }); - set({ searchError: mapErrorCodeToSkillErrorKey(appError.code, 'search') }); + const errorKey = mapErrorCodeToSkillErrorKey(appError.code, 'search'); + set({ searchError: errorKey ?? appError.message }); } finally { set({ searching: false }); } @@ -212,7 +214,8 @@ export const useSkillsStore = create((set, get) => ({ module: 'skills', operation: 'install', }); - throw new Error(mapErrorCodeToSkillErrorKey(appError.code, 'install')); + const errorKey = mapErrorCodeToSkillErrorKey(appError.code, 'install'); + throw new Error(errorKey ?? appError.message); } // Refresh skills after install await get().fetchSkills();