Kareadita/Kavita · warning · KavitaException
sidenav-stream-only-delete-smart-filter
Error message
sidenav-stream-only-delete-smart-filter
What it means
Thrown by StreamService.DeleteSideNavSmartFilterStream when the loaded stream's StreamType is not SideNavStreamType.SmartFilter. Only user-created SmartFilter side-nav entries are deletable through this endpoint; system streams (Libraries, WantToRead, etc.) and external-source streams must be removed through their own flows. It is a localized KavitaException surfaced as HTTP 500.
Source
Thrown at Kavita.Services/StreamService.cs:365
var streams2 = await unitOfWork.UserRepository.GetSideNavStreamWithExternalSource(externalSourceId, ct);
unitOfWork.UserRepository.Delete(streams2);
await unitOfWork.CommitAsync(ct);
}
public async Task DeleteSideNavSmartFilterStream(int userId, int sideNavStreamId, CancellationToken ct = default)
{
try
{
var stream = await unitOfWork.UserRepository.GetSideNavStream(sideNavStreamId, ct);
if (stream == null) throw new KavitaException("sidenav-stream-doesnt-exist");
if (stream.AppUserId != userId) throw new KavitaException("sidenav-stream-doesnt-exist");
if (stream.StreamType != SideNavStreamType.SmartFilter)
{
throw new KavitaException("sidenav-stream-only-delete-smart-filter");
}
unitOfWork.UserRepository.Delete(stream);
await unitOfWork.CommitAsync(ct);
}
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);View on GitHub (pinned to 9c3e540000)
Solutions
- Gate the delete UI on streamType === 'smartFilter'; hide delete for system and external-source streams.
- For external-source streams, delete via DELETE /api/streams/delete-external-source instead.
- If the user wants to hide (not delete) a non-smart-filter stream, use update-sidenav-stream to set visible=false.
Example fix
// before
canDelete(s: SideNavStreamDto) { return true; }
// after
canDelete(s: SideNavStreamDto) { return s.streamType === 'smartFilter'; } Defensive patterns
Strategy: type-guard
Validate before calling
function isSmartFilterStream(s: SideNavStreamDto): boolean {
return s?.streamType === 'smartFilter';
} Type guard
function isDeletableSideNavStream(s: SideNavStreamDto): s is SideNavStreamDto {
return s?.streamType === 'smartFilter';
} Try / catch
on 'sidenav-stream-only-delete-smart-filter', hide the delete control for that stream and switch the user to hide (visible=false) or the external-source delete flow
Prevention
- Show delete only for streamType === 'smartFilter'.
- Route external-source stream removal through delete-external-source.
- Use update-sidenav-stream (visible=false) to hide non-deletable streams.
When it happens
Trigger: DELETE /api/streams/smart-filter-side-nav-stream?sideNavStreamId=N where the stream exists and is owned by the user but its StreamType is not SmartFilter (e.g., an external-source or built-in stream).
Common situations: The UI shows a delete affordance on a non-smart-filter stream; an external-source side-nav stream is removed via the wrong endpoint (use delete-external-source flow instead); a built-in stream is targeted.
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/c5b5790462092f63.
Report an issue: GitHub.