{"record":{"id":"3bc4da42371d1187","repo":"linshenkx/prompt-optimizer","slug":"category-already-exists-category-name","errorCode":null,"errorMessage":"Category already exists: ${category.name}","messagePattern":"Category already exists: (.+?)","errorType":"validation","errorClass":"FavoriteValidationError","httpStatus":null,"severity":"warning","filePath":"packages/core/src/services/favorite/manager.ts","lineNumber":676,"sourceCode":"    }\n\n    const now = Date.now();\n    const id = `cat_${now}_${Math.random().toString(36).substr(2, 9)}`;\n\n    const newCategory: FavoriteCategory = {\n      ...category,\n      id,\n      createdAt: now,\n      sortOrder: category.sortOrder || 0\n    };\n\n    try {\n      await this.storageProvider.updateData(this.STORAGE_KEYS.CATEGORIES, (categories: FavoriteCategory[] | null) => {\n        const categoriesList = categories || [];\n        // 检查是否已存在同名分类\n        const existing = categoriesList.find(c => c.name === category.name);\n        if (existing) {\n          throw new FavoriteValidationError(`Category already exists: ${category.name}`);\n        }\n        return [...categoriesList, newCategory];\n      });\n\n      return id;\n    } catch (error) {\n      if (error instanceof FavoriteError) {\n        throw error;\n      }\n      const errorMessage = error instanceof Error ? error.message : String(error);\n      throw new FavoriteStorageError(`Failed to add category: ${errorMessage}`);\n    }\n  }\n\n  async updateCategory(id: string, updates: Partial<FavoriteCategory>): Promise<void> {\n    try {\n      await this.storageProvider.updateData(this.STORAGE_KEYS.CATEGORIES, (categories: FavoriteCategory[] | null) => {\n        const categoriesList = categories || [];","sourceCodeStart":658,"sourceCodeEnd":694,"githubUrl":"https://github.com/linshenkx/prompt-optimizer/blob/3e677b1d9f7e0493c142c175560531e7ae786dce/packages/core/src/services/favorite/manager.ts#L658-L694","documentation":"Thrown by FavoriteManager.addCategory when a category with the same name already exists in storage. The library enforces unique category names, so attempting to add a duplicate is treated as a validation error (FavoriteValidationError) rather than silently merging.","triggerScenarios":"Calling addCategory({name: 'Work'}) when a category named 'Work' already exists; also triggered indirectly via ensureDefaultCategories or importFavorites when the imported/default data contains a name that collides with an existing category.","commonSituations":"Importing favorites from a backup into a store that already has default categories; running ensureDefaultCategories twice without deduplication; importing the same export file twice.","solutions":["Check for an existing category by name first (getCategories()) and reuse it instead of adding","When importing, skip or rename duplicate category names before calling importFavorites","Wrap addCategory in try-catch for FavoriteValidationError and treat it as idempotent success"],"exampleFix":"// before\nawait manager.addCategory({ name: 'Work', icon: 'briefcase' });\n\n// after\nconst existing = (await manager.getCategories()).find(c => c.name === 'Work');\nif (!existing) {\n  await manager.addCategory({ name: 'Work', icon: 'briefcase' });\n}","handlingStrategy":"validation","validationCode":"const existing = (await manager.getCategories()).find(c => c.name === newCategory.name);\nif (existing) { /* reuse existing.id */ }","typeGuard":"const isDuplicateCategoryError = (e: unknown) =>\n  e instanceof FavoriteValidationError && e.message.startsWith('Category already exists');","tryCatchPattern":"try { await manager.addCategory(cat); } catch (e) { if (isDuplicateCategoryError(e)) return existing?.id; throw e; }","preventionTips":["Deduplicate category names before importFavorites","Make addCategory flows idempotent by checking names first"],"tags":["favorites","duplicate","category","validation"],"backgroundTag":"duplicate-entry","analyzedSha":"3e677b1d9f7e0493c142c175560531e7ae786dce","analyzedAt":"2026-08-27T21:29:16.709Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}