Kareadita/Kavita · error · KavitaException

device-doesnt-exist

Error message

device-doesnt-exist

What it means

Thrown by DeviceService.SendTo when the target device ID is not found in the database via GetDeviceById(deviceId). This is checked after the SMTP configuration check but before file validation. The device lookup is global (not user-scoped in this code path), so any valid device ID in the system passes.

Source

Thrown at Kavita.Services/DeviceService.cs:107

            if (!unitOfWork.HasChanges()) return true;
            if (await unitOfWork.CommitAsync(ct)) return true;
        }
        catch (Exception ex)
        {
            logger.LogError(ex, "There was an issue with deleting the device, {DeviceId} for user {UserName}", deviceId, userWithDevices.UserName);
        }

        return false;
    }

    public async Task<bool> SendTo(IReadOnlyList<int> chapterIds, int deviceId, CancellationToken ct = default)
    {
        var settings = await unitOfWork.SettingsRepository.GetSettingsDtoAsync(ct);
        if (!settings.IsEmailSetupForSendToDevice())
            throw new KavitaException("send-to-kavita-email");

        var device = await unitOfWork.DeviceRepository.GetDeviceById(deviceId, ct);
        if (device == null) throw new KavitaException("device-doesnt-exist");

        var files = await unitOfWork.ChapterRepository.GetFilesForChaptersAsync(chapterIds, ct);
        if (files.Any(f => f.Format is not (MangaFormat.Epub or MangaFormat.Pdf)) && device.Platform == EmailDevicePlatform.Kindle)
            throw new KavitaException("send-to-permission");

        // If the size of the files is too big
        if (files.Sum(f => f.Bytes) >= settings.SmtpConfig.SizeLimit)
            throw new KavitaException("send-to-size-limit");


        try
        {
            device.UpdateLastUsed();
            unitOfWork.DeviceRepository.Update(device);
            await unitOfWork.CommitAsync(ct);
        }
        catch (Exception ex)
        {

View on GitHub (pinned to 9c3e540000)

Solutions

  1. Refresh the device list and select a currently valid device
  2. Verify the device ID exists by calling the list-devices endpoint before sending
  3. Handle the KavitaException and prompt the user to re-select a device

Example fix

// Validate device exists before calling SendTo:
// var devices = await deviceService.GetDevicesForUser(userId);
// if (!devices.Any(d => d.Id == deviceId)) {
//     return BadRequest('Selected device no longer exists');
// }
Defensive patterns

Strategy: validation

Validate before calling

// Verify the device exists before sending:
// var device = await unitOfWork.DeviceRepository.GetDeviceById(deviceId, ct);
// if (device == null) return NotFound("Device not found");

Try / catch

// try {
//     await deviceService.SendTo(chapterIds, deviceId, ct);
// } catch (KavitaException ex) when (ex.Message == "device-doesnt-exist") {
//     return NotFound(new { error = "The selected device no longer exists." });
// }

Prevention

When it happens

Trigger: User sends to a device that was deleted; device ID in the request is invalid or from a stale list; the device belongs to a different user and is not found in a scoped query elsewhere.

Common situations: Device list is stale in the UI after devices were removed; user bookmarks an old send-to-device link; API client sends a hardcoded device ID that no longer exists.

Related errors


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