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
- Refresh the device list and select a currently valid device
- Verify the device ID exists by calling the list-devices endpoint before sending
- 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
- Refresh the device list before sending to ensure the device ID is current
- Validate the device ID client-side against the active device list
- Handle stale device references with clear error messages and a device list refresh prompt
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.