From c06f93aeda99ae70543dd2232fd0d4fe7ebe21f1 Mon Sep 17 00:00:00 2001 From: GeorgeDong32 Date: Sat, 27 Dec 2025 22:16:11 +0800 Subject: [PATCH] fix(backup): improve error messages to distinguish EBUSY from format errors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes #12160 **Changes**: - Enhanced error handling in BackupService.ts (restore, restoreFromWebdav, restoreFromLocal) - Added specific error messages for EBUSY (file locked) and ENOENT (file not found) - Added i18n support for new error messages in en-us.json and zh-cn.json **Impact**: Users will now see accurate error messages: - EBUSY errors → "Cannot restore: Some files are in use. Please close all knowledge bases or restart the app and try again." - ENOENT errors → "Backup file not found or is corrupted" - JSON errors → "Backup file format error" - Other errors → Detailed error message for debugging **Technical Details**: - Distinguishes error codes (EBUSY, ENOENT) and message content - Provides clear user guidance instead of misleading "file format error" - Step 1 of phased fix plan for #12160 --- src/renderer/src/i18n/locales/en-us.json | 4 +- src/renderer/src/i18n/locales/zh-cn.json | 4 +- src/renderer/src/services/BackupService.ts | 55 +++++++++++++++++++--- 3 files changed, 55 insertions(+), 8 deletions(-) diff --git a/src/renderer/src/i18n/locales/en-us.json b/src/renderer/src/i18n/locales/en-us.json index 45a2222930..559e90b0f4 100644 --- a/src/renderer/src/i18n/locales/en-us.json +++ b/src/renderer/src/i18n/locales/en-us.json @@ -1309,7 +1309,9 @@ "availableProviders": "Available Providers", "availableTools": "Available Tools", "backup": { - "file_format": "Backup file format error" + "file_format": "Backup file format error", + "file_locked": "Cannot restore: Some files are in use. Please close all knowledge bases or restart the app and try again.", + "file_not_found": "Backup file not found or is corrupted" }, "base64DataTruncated": "Base64 image data truncated, size", "boundary": { diff --git a/src/renderer/src/i18n/locales/zh-cn.json b/src/renderer/src/i18n/locales/zh-cn.json index 220a109a74..3e5df577e2 100644 --- a/src/renderer/src/i18n/locales/zh-cn.json +++ b/src/renderer/src/i18n/locales/zh-cn.json @@ -1309,7 +1309,9 @@ "availableProviders": "可用提供商", "availableTools": "可用工具", "backup": { - "file_format": "备份文件格式错误" + "file_format": "备份文件格式错误", + "file_locked": "无法恢复:某些文件正在使用中。请关闭所有知识库或重启应用后重试。", + "file_not_found": "备份文件未找到或已损坏" }, "base64DataTruncated": "Base64 图片数据已截断,大小", "boundary": { diff --git a/src/renderer/src/services/BackupService.ts b/src/renderer/src/services/BackupService.ts index 1c97ebd087..810c306cb8 100644 --- a/src/renderer/src/services/BackupService.ts +++ b/src/renderer/src/services/BackupService.ts @@ -100,9 +100,23 @@ export async function restore() { source: 'backup', channel: 'system' }) - } catch (error) { + } catch (error: any) { logger.error('restore: Error restoring backup file:', error as Error) - window.toast.error(i18n.t('error.backup.file_format')) + + // Distinguish different error types for better user experience + const errorCode = error.code || '' + const errorMessage = error.message || '' + + if (errorCode === 'EBUSY' || errorMessage.includes('EBUSY') || errorMessage.includes('locked')) { + window.toast.error(i18n.t('error.backup.file_locked')) + } else if (errorCode === 'ENOENT' || errorMessage.includes('no such file')) { + window.toast.error(i18n.t('error.backup.file_not_found')) + } else if (errorMessage.includes('JSON')) { + window.toast.error(i18n.t('error.backup.file_format')) + } else { + // Show detailed error message for debugging + window.toast.error(i18n.t('error.backup.file_format') + ': ' + errorMessage) + } } } } @@ -314,9 +328,23 @@ export async function restoreFromWebdav(fileName?: string) { try { await handleData(JSON.parse(data)) - } catch (error) { + } catch (error: any) { logger.error('[Backup] Error downloading file from WebDAV:', error as Error) - window.toast.error(i18n.t('error.backup.file_format')) + + // Distinguish different error types for better user experience + const errorCode = error.code || '' + const errorMessage = error.message || '' + + if (errorCode === 'EBUSY' || errorMessage.includes('EBUSY') || errorMessage.includes('locked')) { + window.toast.error(i18n.t('error.backup.file_locked')) + } else if (errorCode === 'ENOENT' || errorMessage.includes('no such file')) { + window.toast.error(i18n.t('error.backup.file_not_found')) + } else if (errorMessage.includes('JSON')) { + window.toast.error(i18n.t('error.backup.file_format')) + } else { + // Show detailed error message for debugging + window.toast.error(i18n.t('error.backup.file_format') + ': ' + errorMessage) + } } } @@ -1071,9 +1099,24 @@ export async function restoreFromLocal(fileName: string) { await handleData(data) return true - } catch (error) { + } catch (error: any) { logger.error('[LocalBackup] Restore failed:', error as Error) - window.toast.error(i18n.t('error.backup.file_format')) + + // Distinguish different error types for better user experience + const errorCode = error.code || '' + const errorMessage = error.message || '' + + if (errorCode === 'EBUSY' || errorMessage.includes('EBUSY') || errorMessage.includes('locked')) { + window.toast.error(i18n.t('error.backup.file_locked')) + } else if (errorCode === 'ENOENT' || errorMessage.includes('no such file')) { + window.toast.error(i18n.t('error.backup.file_not_found')) + } else if (errorMessage.includes('JSON')) { + window.toast.error(i18n.t('error.backup.file_format')) + } else { + // Show detailed error message for debugging + window.toast.error(i18n.t('error.backup.file_format') + ': ' + errorMessage) + } + throw error } }