{"record":{"id":"cedbc8b42d1bb9ae","repo":"Kareadita/Kavita","slug":"errors-delete-theme-in-use","errorCode":"errors.delete-theme-in-use","errorMessage":"errors.delete-theme-in-use","messagePattern":"errors\\.delete-theme-in-use","errorType":"exception","errorClass":"KavitaException","httpStatus":400,"severity":"warning","filePath":"Kavita.Services/SiteThemeService.cs","lineNumber":396,"sourceCode":"        await eventHub.SendMessageAsync(MessageFactory.NotificationProgress,\n            MessageFactory.SiteThemeProgressEvent(directoryService.FileSystem.Path.GetFileName(theme.FileName), theme.Name,\n                ProgressEventType.Ended));\n\n        logger.LogInformation(\"Theme Sync complete\");\n    }\n\n    /// <summary>\n    /// Deletes a SiteTheme. The CSS file will be moved to temp/ to allow user to recover data\n    /// </summary>\n    /// <param name=\"siteThemeId\"></param>\n    /// <param name=\"ct\"></param>\n    public async Task DeleteTheme(int siteThemeId, CancellationToken ct = default)\n    {\n        // Validate no one else is using this theme\n        var inUse = await unitOfWork.SiteThemeRepository.IsThemeInUse(siteThemeId);\n        if (inUse)\n        {\n            throw new KavitaException(\"errors.delete-theme-in-use\");\n        }\n\n        var siteTheme = await unitOfWork.SiteThemeRepository.GetTheme(siteThemeId);\n        if (siteTheme == null) return;\n\n        await RemoveTheme(siteTheme);\n    }\n\n    /// <summary>\n    /// This assumes a file is already in temp directory and will be used for\n    /// </summary>\n    /// <param name=\"tempFile\"></param>\n    /// <param name=\"username\"></param>\n    /// <param name=\"ct\"></param>\n    /// <returns></returns>\n    public async Task<SiteTheme> CreateThemeFromFile(string tempFile, string username, CancellationToken ct = default)\n    {\n        if (!directoryService.FileSystem.File.Exists(tempFile))","sourceCodeStart":378,"sourceCodeEnd":414,"githubUrl":"https://github.com/Kareadita/Kavita/blob/9c3e5400007f8a0282f7d883f2ad5e71716e514d/Kavita.Services/SiteThemeService.cs#L378-L414","documentation":"Thrown by SiteThemeService.DeleteTheme when SiteThemeRepository.IsThemeInUse(siteThemeId) is true, i.e. at least one user has this theme selected as their active preference. Kavita protects users from losing their theme by blocking deletion; it throws KavitaException('errors.delete-theme-in-use'). ThemeController.DeleteTheme does not catch it, so it bubbles to ExceptionMiddleware and returns HTTP 500 with the raw key string 'errors.delete-theme-in-use'.","triggerScenarios":"DELETE /api/theme?themeId=N while one or more AppUserPreferences rows still reference that theme as the user's Theme.","commonSituations":"Admin deletes a theme that the whole server or a single user has active; users who picked a custom theme never switched back to a default before the admin removes it.","solutions":["Have every user using the theme switch to a different theme (or default), then retry the delete.","As admin, bulk-reset affected users' theme preference to the default, then delete.","Re-list themes and confirm none reference the target before deleting."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  await api.delete(`/api/theme?themeId=${themeId}`);\n} catch (e) {\n  // HTTP 500 with raw key 'errors.delete-theme-in-use': users still have it active.\n  notify('Theme is in use by at least one user. Have them switch themes first.');\n}","preventionTips":["Before deleting, ask users on that theme to switch to a default.","Admin can bulk-reset affected users' theme preference to the default, then delete.","Re-list themes after delete to keep client state consistent."],"tags":["theme","validation","user-state","delete","admin"],"backgroundTag":null,"analyzedSha":"9c3e5400007f8a0282f7d883f2ad5e71716e514d","analyzedAt":"2026-08-13T19:06:05.897Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}