Kareadita/Kavita · error · KavitaException

reading-list-name-exists

reading-list-name-exists

Error message

reading-list-name-exists

What it means

Thrown by ReadingListService.CreateReadingListForUser when a reading list with the same NormalizedTitle already exists for the user. Kavita normalizes titles (ToNormalized) so casing/punctuation differences don't create near-duplicate lists; the uniqueness check is on the normalized form, not the raw title.

Source

Thrown at Kavita.Services/ReadingLists/ReadingListService.cs:59

    IDirectoryService directoryService,
    IEntityNamingService namingService)
    : IReadingListService
{
    /// <summary>
    /// Creates a new Reading List for a User
    /// </summary>
    /// <param name="userWithReadingList"></param>
    /// <param name="title"></param>
    /// <returns></returns>
    /// <exception cref="KavitaException"></exception>
    public async Task<ReadingList> CreateReadingListForUser(AppUser userWithReadingList, string title)
    {
        // When creating, we need to make sure Title is unique
        var normalizedTitle = title.ToNormalized();
        var hasExisting = userWithReadingList.ReadingLists.Any(l => l.NormalizedTitle == normalizedTitle);
        if (hasExisting)
        {
            throw new KavitaException("reading-list-name-exists");
        }

        var readingList = new ReadingListBuilder(title).Build();
        userWithReadingList.ReadingLists.Add(readingList);

        if (!unitOfWork.HasChanges()) throw new KavitaException("generic-reading-list-create");
        await unitOfWork.CommitAsync();
        return readingList;
    }

    /// <summary>
    ///
    /// </summary>
    /// <param name="readingList"></param>
    /// <param name="dto"></param>
    /// <exception cref="KavitaException"></exception>
    public async Task UpdateReadingList(ReadingList readingList, UpdateReadingListDto dto)
    {

View on GitHub (pinned to 9c3e540000)

Solutions

  1. Check userWithReadingList.ReadingLists for a matching normalized title before calling create, and prompt the user to pick a unique name.
  2. If importing, de-duplicate titles by normalized form upstream.
  3. Rename or delete the existing conflicting list first.
  4. Ensure the client uses the same normalization (Parser.Normalize / ToNormalized) when pre-validating.

Example fix

// before
var list = await readingListService.CreateReadingListForUser(user, title);

// after
var normalized = title.ToNormalized();
if (user.ReadingLists.Any(l => l.NormalizedTitle == normalized))
    return Conflict($"A reading list named '{title}' already exists");
var list = await readingListService.CreateReadingListForUser(user, title);
Defensive patterns

Strategy: validation

Validate before calling

var normalized = title.ToNormalized();
if (userWithReadingList.ReadingLists.Any(l => l.NormalizedTitle == normalized))
    return Conflict($"Reading list '{title}' already exists");
var list = await readingListService.CreateReadingListForUser(userWithReadingList, title);

Type guard

static bool IsUniqueTitle(string title, IEnumerable<ReadingList> existing) => !existing.Any(l => l.NormalizedTitle == title.ToNormalized());

Prevention

When it happens

Trigger: Calling CreateReadingListForUser with a title whose normalized form collides with an existing entry in userWithReadingList.ReadingLists (e.g. 'My List' vs 'my-list' both normalize to the same key).

Common situations: User creates a list with a name differing only by case/spacing from an existing one; a bulk import of reading lists contains duplicates; or the normalized-title index drifted from raw titles after a normalization change.

Related errors


AI-assisted analysis of Kareadita/Kavita@9c3e540000 (2026-08-13). Data as JSON: /api/errors/958c24de190e1014. Report an issue: GitHub.