{"record":{"id":"c5b5790462092f63","repo":"Kareadita/Kavita","slug":"sidenav-stream-only-delete-smart-filter","errorCode":null,"errorMessage":"sidenav-stream-only-delete-smart-filter","messagePattern":"sidenav-stream-only-delete-smart-filter","errorType":"exception","errorClass":"KavitaException","httpStatus":400,"severity":"warning","filePath":"Kavita.Services/StreamService.cs","lineNumber":365,"sourceCode":"        var streams2 = await unitOfWork.UserRepository.GetSideNavStreamWithExternalSource(externalSourceId, ct);\n        unitOfWork.UserRepository.Delete(streams2);\n\n        await unitOfWork.CommitAsync(ct);\n    }\n\n    public async Task DeleteSideNavSmartFilterStream(int userId, int sideNavStreamId, CancellationToken ct = default)\n    {\n        try\n        {\n            var stream = await unitOfWork.UserRepository.GetSideNavStream(sideNavStreamId, ct);\n            if (stream == null) throw new KavitaException(\"sidenav-stream-doesnt-exist\");\n\n            if (stream.AppUserId != userId) throw new KavitaException(\"sidenav-stream-doesnt-exist\");\n\n\n            if (stream.StreamType != SideNavStreamType.SmartFilter)\n            {\n                throw new KavitaException(\"sidenav-stream-only-delete-smart-filter\");\n            }\n\n            unitOfWork.UserRepository.Delete(stream);\n\n            await unitOfWork.CommitAsync(ct);\n        }\n        catch (Exception ex)\n        {\n            logger.LogError(ex, \"There was an exception deleting SideNav Smart Filter Stream: {FilterId}\", sideNavStreamId);\n            throw;\n        }\n    }\n\n    public async Task DeleteDashboardSmartFilterStream(int userId, int dashboardStreamId, CancellationToken ct = default)\n    {\n        try\n        {\n            var stream = await unitOfWork.UserRepository.GetDashboardStream(dashboardStreamId, ct);","sourceCodeStart":347,"sourceCodeEnd":383,"githubUrl":"https://github.com/Kareadita/Kavita/blob/9c3e5400007f8a0282f7d883f2ad5e71716e514d/Kavita.Services/StreamService.cs#L347-L383","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","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."],"exampleFix":"// before\ncanDelete(s: SideNavStreamDto) { return true; }\n// after\ncanDelete(s: SideNavStreamDto) { return s.streamType === 'smartFilter'; }","handlingStrategy":"type-guard","validationCode":"function isSmartFilterStream(s: SideNavStreamDto): boolean {\n  return s?.streamType === 'smartFilter';\n}","typeGuard":"function isDeletableSideNavStream(s: SideNavStreamDto): s is SideNavStreamDto {\n  return s?.streamType === 'smartFilter';\n}","tryCatchPattern":"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","preventionTips":["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."],"tags":["sidenav","validation","business-rule"],"backgroundTag":null,"analyzedSha":"9c3e5400007f8a0282f7d883f2ad5e71716e514d","analyzedAt":"2026-08-13T19:06:05.897Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}