Kareadita/Kavita · error · KavitaException
collection-doesnt-exist
Error message
collection-doesnt-exist
What it means
Thrown by UpdateTag when the collection tag with the given dto.Id does not exist in the database. GetCollectionAsync(dto.Id) returns null, indicating the collection was deleted or the ID is invalid. It is the first validation in the update flow, checked before ownership and title validation.
Source
Thrown at Kavita.Services/CollectionTagService.cs:37
public class CollectionTagService(IUnitOfWork unitOfWork, IEventHub eventHub, IDirectoryService directoryService) : ICollectionTagService
{
public async Task<bool> DeleteTag(int tagId, AppUser user, CancellationToken ct = default)
{
var collectionTag = await unitOfWork.CollectionTagRepository.GetCollectionAsync(tagId, ct: ct);
if (collectionTag == null) return true;
user.Collections.Remove(collectionTag);
if (!unitOfWork.HasChanges()) return true;
return await unitOfWork.CommitAsync(ct);
}
public async Task<bool> UpdateTag(AppUserCollectionDto dto, int userId, CancellationToken ct = default)
{
var existingTag = await unitOfWork.CollectionTagRepository.GetCollectionAsync(dto.Id, ct: ct);
if (existingTag == null) throw new KavitaException("collection-doesnt-exist");
if (existingTag.AppUserId != userId) throw new KavitaException("access-denied");
var title = dto.Title.Trim();
if (string.IsNullOrEmpty(title)) throw new KavitaException("collection-tag-title-required");
// Ensure the title doesn't exist on the user's account already
if (!title.Equals(existingTag.Title) && await unitOfWork.CollectionTagRepository.CollectionExists(dto.Title, userId, ct))
throw new KavitaException("collection-tag-duplicate");
existingTag.Items ??= [];
if (existingTag.Source == ScrobbleProvider.Kavita)
{
existingTag.Title = title;
existingTag.NormalizedTitle = dto.Title.ToNormalized();
}
var roles = await unitOfWork.UserRepository.GetRoles(userId, ct);
if (roles.Contains(PolicyConstants.AdminRole) || roles.Contains(PolicyConstants.PromoteRole))View on GitHub (pinned to 9c3e540000)
Solutions
- Refresh the collections list in the UI and confirm the collection still exists before editing
- Verify the collection ID matches one returned by the user's collections endpoint
- Handle the KavitaException gracefully in the controller and return a 404 to the client
Example fix
// Guard in the calling controller: // var collection = await collectionService.GetCollection(dto.Id, userId); // if (collection == null) return NotFound();
Defensive patterns
Strategy: try-catch
Validate before calling
// Verify collection exists before updating:
// var collection = await unitOfWork.CollectionTagRepository.GetCollectionAsync(dto.Id, ct: ct);
// if (collection == null) return NotFound("Collection not found");
// if (collection.AppUserId != userId) return Forbid(); Try / catch
// try {
// await collectionTagService.UpdateTag(dto, userId, ct);
// return Ok();
// } catch (KavitaException ex) {
// return ex.Message switch {
// "collection-doesnt-exist" => NotFound(),
// "access-denied" => Forbid(),
// _ => BadRequest(ex.Message)
// };
// } Prevention
- Refresh collections list before editing to avoid stale IDs
- Handle concurrent deletion scenarios with graceful 404 responses
- Consider optimistic concurrency tokens for collection edits
When it happens
Trigger: User edits a collection that was deleted in another session; the collection ID in the request is from a different user; a race condition where the collection is removed between the client loading the edit form and submitting changes.
Common situations: Multiple browser tabs or users managing collections concurrently; stale UI after collections were bulk-deleted; bookmarked URL pointing to a removed collection.
Related errors
- device-not-created
- collection-doesnt-exist
- library-doesnt-exist
- client-device-doesnt-exist
- collection-tag-title-required
AI-assisted analysis of Kareadita/Kavita@9c3e540000 (2026-08-13).
Data as JSON: /api/errors/e2d69205a5eac3dc.
Report an issue: GitHub.