Kareadita/Kavita · error · KavitaException
reading-list-title-required
reading-list-title-required
Error message
reading-list-title-required
What it means
Thrown by ReadingListService.UpdateReadingList after trimming dto.Title, when the result is null or empty. A reading list must always have a non-empty title, so an update that would clear it is rejected before any persistence.
Source
Thrown at Kavita.Services/ReadingLists/ReadingListService.cs:79
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)
{
dto.Title = dto.Title.Trim();
if (string.IsNullOrEmpty(dto.Title)) throw new KavitaException("reading-list-title-required");
if (!dto.Title.Equals(readingList.Title) && await unitOfWork.ReadingListRepository.ReadingListExists(dto.Title, readingList.Id))
throw new KavitaException("reading-list-name-exists");
readingList.Summary = dto.Summary;
readingList.Title = dto.Title.Trim();
readingList.NormalizedTitle = Parser.Normalize(readingList.Title);
readingList.Promoted = dto.Promoted;
readingList.CoverImageLocked = dto.CoverImageLocked;
if (readingList.Tags == null)
{
throw new ArgumentException("You must pass a Reading List with tags included");
}
await TagHelper.UpdateEntityTags(readingList.Tags, dto.Tags, unitOfWork.DataContext.ReadingListTag, unitOfWork, false);
View on GitHub (pinned to 9c3e540000)
Solutions
- Require a non-empty title in the client form before enabling save.
- Server-side DTO validation: add [Required] / [MinLength(1)] on UpdateReadingListDto.Title.
- If the title is optional for the patch, skip the assignment when empty instead of throwing.
- Return the localized 'reading-list-title-required' message to the user so they re-enter a name.
Example fix
// before
await readingListService.UpdateReadingList(list, dto);
// after - DTO validation
public class UpdateReadingListDto
{
[Required] public string Title { get; set; } = string.Empty;
}
// controller returns 400 automatically before the service is reached Defensive patterns
Strategy: validation
Validate before calling
if (string.IsNullOrWhiteSpace(dto?.Title))
return BadRequest("reading-list-title-required");
await readingListService.UpdateReadingList(list, dto); Type guard
static bool HasNonEmptyTitle(UpdateReadingListDto dto) => !string.IsNullOrWhiteSpace(dto?.Title);
Prevention
- Add [Required] on UpdateReadingListDto.Title for automatic 400s.
- Disable save in the UI when the title field is empty.
- Reject empty titles before reaching the service.
When it happens
Trigger: PUT/PATCH update of a reading list where dto.Title is null, empty, or only whitespace (after .Trim() it becomes empty).
Common situations: Frontend sent an empty title field; a user cleared the title input; or a bulk update script passed null title to 'reset' it.
Related errors
- reading-list-name-exists
- generic-reading-list-create
- external-source-required
- {comparison} is not applicable for {fieldName}
- Name must be set
AI-assisted analysis of Kareadita/Kavita@9c3e540000 (2026-08-13).
Data as JSON: /api/errors/440beee58fe07947.
Report an issue: GitHub.