Kareadita/Kavita · warning · KavitaException
dashboard-stream-only-delete-smart-filter
Error message
dashboard-stream-only-delete-smart-filter
What it means
Thrown by StreamService.DeleteDashboardSmartFilterStream when the loaded stream's StreamType is not DashboardStreamType.SmartFilter. Only user-created SmartFilter dashboard entries are deletable here; built-in dashboard widgets must be hidden via update-dashboard-stream, not deleted. It is a localized KavitaException surfaced as HTTP 500.
Source
Thrown at Kavita.Services/StreamService.cs:390
catch (Exception ex)
{
logger.LogError(ex, "There was an exception deleting SideNav Smart Filter Stream: {FilterId}", sideNavStreamId);
throw;
}
}
public async Task DeleteDashboardSmartFilterStream(int userId, int dashboardStreamId, CancellationToken ct = default)
{
try
{
var stream = await unitOfWork.UserRepository.GetDashboardStream(dashboardStreamId, ct);
if (stream == null) throw new KavitaException("dashboard-stream-doesnt-exist");
if (stream.AppUserId != userId) throw new KavitaException("dashboard-stream-doesnt-exist");
if (stream.StreamType != DashboardStreamType.SmartFilter)
{
throw new KavitaException("dashboard-stream-only-delete-smart-filter");
}
unitOfWork.UserRepository.Delete(stream);
await unitOfWork.CommitAsync(ct);
} catch (Exception ex)
{
logger.LogError(ex, "There was an exception deleting Dashboard Smart Filter Stream: {FilterId}", dashboardStreamId);
throw;
}
}
public async Task RenameSmartFilterStreams(AppUserSmartFilter smartFilter, CancellationToken ct = default)
{
var sideNavStreams = await unitOfWork.UserRepository.GetSideNavStreamWithFilter(smartFilter.Id, ct);
var dashboardStreams = await unitOfWork.UserRepository.GetDashboardStreamWithFilter(smartFilter.Id, ct);
foreach (var sideNavStream in sideNavStreams)View on GitHub (pinned to 9c3e540000)
Solutions
- Gate the delete UI on streamType === 'smartFilter'; hide delete for built-in dashboard widgets.
- To remove a built-in widget from the dashboard, POST update-dashboard-stream with visible=false instead.
- If a smart-filter must be removed, confirm its type before showing the delete control.
Example fix
// before
canDelete(s: DashboardStreamDto) { return true; }
// after
canDelete(s: DashboardStreamDto) { return s.streamType === 'smartFilter'; } Defensive patterns
Strategy: type-guard
Validate before calling
function isSmartFilterDashboardStream(s: DashboardStreamDto): boolean {
return s?.streamType === 'smartFilter';
} Type guard
function isDeletableDashboardStream(s: DashboardStreamDto): s is DashboardStreamDto {
return s?.streamType === 'smartFilter';
} Try / catch
on 'dashboard-stream-only-delete-smart-filter', hide the delete control and offer update-dashboard-stream (visible=false) instead
Prevention
- Show delete only for streamType === 'smartFilter'.
- Hide built-in widgets via update-dashboard-stream, not delete.
- Confirm the type before showing the delete control.
When it happens
Trigger: DELETE /api/streams/smart-filter-dashboard-stream?dashboardStreamId=N where the stream exists and is owned by the user but its StreamType is not SmartFilter (e.g., a built-in dashboard widget).
Common situations: The UI offers delete on a built-in dashboard stream; the user expects to remove a system widget through the delete endpoint instead of hiding it.
Related errors
- name-already-in-use
- cant-delete-default-profile
- cant-assign-devices-to-default
- reading-profiles-device-overlap
- reading-list-name-exists
AI-assisted analysis of Kareadita/Kavita@9c3e540000 (2026-08-13).
Data as JSON: /api/errors/255590a9faf3099a.
Report an issue: GitHub.