Kareadita/Kavita · warning · KavitaException
errors.delete-theme-in-use
errors.delete-theme-in-use
Error message
errors.delete-theme-in-use
What it means
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'.
Source
Thrown at Kavita.Services/SiteThemeService.cs:396
await eventHub.SendMessageAsync(MessageFactory.NotificationProgress,
MessageFactory.SiteThemeProgressEvent(directoryService.FileSystem.Path.GetFileName(theme.FileName), theme.Name,
ProgressEventType.Ended));
logger.LogInformation("Theme Sync complete");
}
/// <summary>
/// Deletes a SiteTheme. The CSS file will be moved to temp/ to allow user to recover data
/// </summary>
/// <param name="siteThemeId"></param>
/// <param name="ct"></param>
public async Task DeleteTheme(int siteThemeId, CancellationToken ct = default)
{
// Validate no one else is using this theme
var inUse = await unitOfWork.SiteThemeRepository.IsThemeInUse(siteThemeId);
if (inUse)
{
throw new KavitaException("errors.delete-theme-in-use");
}
var siteTheme = await unitOfWork.SiteThemeRepository.GetTheme(siteThemeId);
if (siteTheme == null) return;
await RemoveTheme(siteTheme);
}
/// <summary>
/// This assumes a file is already in temp directory and will be used for
/// </summary>
/// <param name="tempFile"></param>
/// <param name="username"></param>
/// <param name="ct"></param>
/// <returns></returns>
public async Task<SiteTheme> CreateThemeFromFile(string tempFile, string username, CancellationToken ct = default)
{
if (!directoryService.FileSystem.File.Exists(tempFile))View on GitHub (pinned to 9c3e540000)
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.
Defensive patterns
Strategy: try-catch
Try / catch
try {
await api.delete(`/api/theme?themeId=${themeId}`);
} catch (e) {
// HTTP 500 with raw key 'errors.delete-theme-in-use': users still have it active.
notify('Theme is in use by at least one user. Have them switch themes first.');
} Prevention
- 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.
When it happens
Trigger: DELETE /api/theme?themeId=N while one or more AppUserPreferences rows still reference that theme as the user's Theme.
Common situations: 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.
Related errors
AI-assisted analysis of Kareadita/Kavita@9c3e540000 (2026-08-13).
Data as JSON: /api/errors/cedbc8b42d1bb9ae.
Report an issue: GitHub.