{"record":{"id":"255590a9faf3099a","repo":"Kareadita/Kavita","slug":"dashboard-stream-only-delete-smart-filter","errorCode":null,"errorMessage":"dashboard-stream-only-delete-smart-filter","messagePattern":"dashboard-stream-only-delete-smart-filter","errorType":"exception","errorClass":"KavitaException","httpStatus":400,"severity":"warning","filePath":"Kavita.Services/StreamService.cs","lineNumber":390,"sourceCode":"        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);\n            if (stream == null) throw new KavitaException(\"dashboard-stream-doesnt-exist\");\n\n            if (stream.AppUserId != userId) throw new KavitaException(\"dashboard-stream-doesnt-exist\");\n\n            if (stream.StreamType != DashboardStreamType.SmartFilter)\n            {\n                throw new KavitaException(\"dashboard-stream-only-delete-smart-filter\");\n            }\n\n            unitOfWork.UserRepository.Delete(stream);\n\n            await unitOfWork.CommitAsync(ct);\n        } catch (Exception ex)\n        {\n            logger.LogError(ex, \"There was an exception deleting Dashboard Smart Filter Stream: {FilterId}\", dashboardStreamId);\n            throw;\n        }\n    }\n\n    public async Task RenameSmartFilterStreams(AppUserSmartFilter smartFilter, CancellationToken ct = default)\n    {\n        var sideNavStreams = await unitOfWork.UserRepository.GetSideNavStreamWithFilter(smartFilter.Id, ct);\n        var dashboardStreams = await unitOfWork.UserRepository.GetDashboardStreamWithFilter(smartFilter.Id, ct);\n\n        foreach (var sideNavStream in sideNavStreams)","sourceCodeStart":372,"sourceCodeEnd":408,"githubUrl":"https://github.com/Kareadita/Kavita/blob/9c3e5400007f8a0282f7d883f2ad5e71716e514d/Kavita.Services/StreamService.cs#L372-L408","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","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."],"exampleFix":"// before\ncanDelete(s: DashboardStreamDto) { return true; }\n// after\ncanDelete(s: DashboardStreamDto) { return s.streamType === 'smartFilter'; }","handlingStrategy":"type-guard","validationCode":"function isSmartFilterDashboardStream(s: DashboardStreamDto): boolean {\n  return s?.streamType === 'smartFilter';\n}","typeGuard":"function isDeletableDashboardStream(s: DashboardStreamDto): s is DashboardStreamDto {\n  return s?.streamType === 'smartFilter';\n}","tryCatchPattern":"on 'dashboard-stream-only-delete-smart-filter', hide the delete control and offer update-dashboard-stream (visible=false) instead","preventionTips":["Show delete only for streamType === 'smartFilter'.","Hide built-in widgets via update-dashboard-stream, not delete.","Confirm the type before showing the delete control."],"tags":["dashboard","validation","business-rule"],"backgroundTag":null,"analyzedSha":"9c3e5400007f8a0282f7d883f2ad5e71716e514d","analyzedAt":"2026-08-13T19:06:05.897Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}