Kareadita/Kavita · warning · KavitaException
errors.theme-already-in-use
errors.theme-already-in-use
Error message
errors.theme-already-in-use
What it means
Thrown by SiteThemeService.CreateThemeFromFile when a theme with the same name already exists. The theme name is derived from the uploaded filename without its extension, and GetThemeDtoByName(themeName) returns non-null. KavitaException('errors.theme-already-in-use') is thrown. ThemeController's upload-theme endpoint does not catch it, so it surfaces as HTTP 500 with the raw key 'errors.theme-already-in-use'.
Source
Thrown at Kavita.Services/SiteThemeService.cs:426
/// <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))
{
logger.LogInformation("Unable to create theme from manual upload as file not in temp");
throw new KavitaException("errors.theme-manual-upload");
}
var filename = directoryService.FileSystem.FileInfo.New(tempFile).Name;
var themeName = Path.GetFileNameWithoutExtension(filename);
if (await unitOfWork.SiteThemeRepository.GetThemeDtoByName(themeName) != null)
{
throw new KavitaException("errors.theme-already-in-use");
}
directoryService.CopyFileToDirectory(tempFile, directoryService.SiteThemeDirectory);
var finalLocation = directoryService.FileSystem.Path.Join(directoryService.SiteThemeDirectory, filename);
// Create a new entry and note that this is downloaded
var theme = new SiteTheme()
{
Name = Path.GetFileNameWithoutExtension(filename),
NormalizedName = themeName.ToNormalized(),
FileName = directoryService.FileSystem.Path.GetFileName(finalLocation),
Provider = ThemeProvider.Custom,
IsDefault = false,
Description = $"Manually uploaded via UI by {username}",
PreviewUrls = string.Empty,
Author = username,
};View on GitHub (pinned to 9c3e540000)
Solutions
- Rename the .css file before uploading so its base name is unique.
- List existing themes via GET /api/theme and pick a non-colliding name.
- If the existing theme is no longer wanted and not in use, delete it first (see errors.delete-theme-in-use), then re-upload.
Example fix
// before
upload('dark.css') // collides with built-in Dark
// after
upload('dark-custom.css') // unique name Defensive patterns
Strategy: validation
Validate before calling
// Derive the theme name the same way the server does (filename without extension), then check uniqueness.
const baseName = file.name.replace(/\.css$/i, '');
const themes: SiteThemeDto[] = await api.get('/api/theme');
const taken = new Set(themes.map(t => t.name.toLowerCase()));
if (taken.has(baseName.toLowerCase())) {
showError('A theme with that name already exists');
return;
}
await api.uploadTheme(file); Type guard
function isThemeNameUnique(baseName: string, themes: { name: string }[]): boolean {
const taken = new Set(themes.map(t => t.name.toLowerCase()));
return !taken.has(baseName.toLowerCase());
} Prevention
- Compare against existing theme names case-insensitively before uploading.
- Avoid colliding with built-in names like 'Dark'.
- Rename the file rather than deleting an in-use existing theme.
When it happens
Trigger: POST /api/theme/upload-theme with a .css file whose base name matches an existing theme name, including shipped built-ins (e.g. 'Dark').
Common situations: Re-uploading a theme already installed; uploading a file whose name collides with a built-in or previously-downloaded theme; case-only differences that normalize to the same name.
Related errors
- errors.delete-theme-in-use
- errors.theme-manual-upload
- invalid-filename
- collection-tag-duplicate
- name-already-in-use
AI-assisted analysis of Kareadita/Kavita@9c3e540000 (2026-08-13).
Data as JSON: /api/errors/8e2cae6da33de0c7.
Report an issue: GitHub.