Kareadita/Kavita · warning · KavitaException

device-duplicate

Error message

device-duplicate

What it means

Thrown by DeviceService.Create when a device with the same name already exists in the user's device list. The check 'userWithDevices.Devices.SingleOrDefault(d => d.Name!.Equals(dto.Name))' performs a case-sensitive exact match on the device name. Device names must be unique per user.

Source

Thrown at Kavita.Services/DeviceService.cs:34

using Kavita.Models.Entities.User;
using Microsoft.Extensions.Logging;

namespace Kavita.Services;

public class DeviceService(
    IUnitOfWork unitOfWork,
    ILogger<DeviceService> logger,
    IEmailService emailService,
    IReadingProfileService readingProfileService)
    : IDeviceService
{
    public async Task<Device?> Create(CreateEmailDeviceDto dto, AppUser userWithDevices, CancellationToken ct = default)
    {
        try
        {
            userWithDevices.Devices ??= new List<Device>();
            var existingDevice = userWithDevices.Devices.SingleOrDefault(d => d.Name!.Equals(dto.Name));
            if (existingDevice != null) throw new KavitaException("device-duplicate");

            existingDevice = new DeviceBuilder(dto.Name)
                .WithPlatform(dto.Platform)
                .WithEmail(dto.EmailAddress)
                .Build();


            userWithDevices.Devices.Add(existingDevice);
            unitOfWork.UserRepository.Update(userWithDevices);

            if (!unitOfWork.HasChanges()) return existingDevice;
            if (await unitOfWork.CommitAsync(ct)) return existingDevice;
        }
        catch (Exception ex)
        {
            logger.LogError(ex, "There was an error when creating your device");
            await unitOfWork.RollbackAsync(ct);
        }

View on GitHub (pinned to 9c3e540000)

Solutions

  1. Choose a different, unique name for the new device
  2. Refresh the device list in the UI before creating to see current names
  3. If the existing device is the same one, update it instead of creating a new one
  4. Add client-side duplicate name checking before form submission

Example fix

// Client-side guard:
// const existing = devices.value.find(d => d.name === dto.name);
// if (existing) { toast.error('A device with this name already exists'); return; }
Defensive patterns

Strategy: validation

Validate before calling

// Check for existing device name before creation:
// var existing = userWithDevices.Devices?.FirstOrDefault(d => d.Name!.Equals(dto.Name));
// if (existing != null) {
//     return BadRequest("A device with this name already exists");
// }

Try / catch

// try {
//     var device = await deviceService.Create(dto, userWithDevices, ct);
//     return Ok(device);
// } catch (KavitaException ex) when (ex.Message == "device-duplicate") {
//     return BadRequest(new { error = "A device with this name already exists." });
// }

Prevention

When it happens

Trigger: User creates a new email device with a name identical to an existing one; the UI did not refresh the device list after a previous creation; user re-submits a form after a double-click.

Common situations: Double-submit from the client creating the same device twice; user forgets they already set up a device with that name; importing or restoring a device configuration that conflicts with existing names.

Related errors


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