{"record":{"id":"e6224515294dde7b","repo":"Kareadita/Kavita","slug":"sidenav-stream-doesnt-exist","errorCode":null,"errorMessage":"sidenav-stream-doesnt-exist","messagePattern":"sidenav-stream-doesnt-exist","errorType":"exception","errorClass":"KavitaException","httpStatus":400,"severity":"warning","filePath":"Kavita.Services/StreamService.cs","lineNumber":244,"sourceCode":"            {\n                Host = externalSource.Host,\n                Id = externalSource.Id,\n                Name = externalSource.Name,\n                ApiKey = externalSource.ApiKey\n            }\n        };\n\n\n        await eventHub.SendMessageToAsync(MessageFactory.SideNavUpdate, MessageFactory.SideNavUpdateEvent(userId),\n            userId, ct);\n        return ret;\n    }\n\n    public async Task UpdateSideNavStream(int userId, SideNavStreamDto dto, CancellationToken ct = default)\n    {\n        var stream = await unitOfWork.UserRepository.GetSideNavStream(dto.Id, ct);\n        if (stream == null)\n            throw new KavitaException(await localizationService.TranslateAsync(userId, \"sidenav-stream-doesnt-exist\"));\n\n        stream.Visible = dto.Visible;\n\n        unitOfWork.UserRepository.Update(stream);\n        await unitOfWork.CommitAsync(ct);\n        await eventHub.SendMessageToAsync(MessageFactory.SideNavUpdate, MessageFactory.SideNavUpdateEvent(userId),\n            userId, ct);\n    }\n\n    public async Task UpdateSideNavStreamPosition(int userId, UpdateStreamPositionDto dto, CancellationToken ct = default)\n    {\n        var user = await unitOfWork.UserRepository.GetUserByIdAsync(userId,\n            AppUserIncludes.SideNavStreams, ct);\n        var stream = user?.SideNavStreams.FirstOrDefault(d => d.Id == dto.Id);\n        if (stream == null) throw new KavitaException(await localizationService.TranslateAsync(userId, \"sidenav-stream-doesnt-exist\"));\n\n        if (stream.Order == dto.ToPosition) return;\n","sourceCodeStart":226,"sourceCodeEnd":262,"githubUrl":"https://github.com/Kareadita/Kavita/blob/9c3e5400007f8a0282f7d883f2ad5e71716e514d/Kavita.Services/StreamService.cs#L226-L262","documentation":"Thrown by StreamService.UpdateSideNavStream when GetSideNavStream(dto.Id) returns null, i.e. no AppUserSideNavStream exists with the given Id. This method updates only the Visible flag; notably the repository lookup is by stream Id alone and performs NO ownership (AppUserId) check, so the same error covers both 'does not exist' and 'belongs to another user' only indirectly (a foreign user's existing stream id would NOT throw here). As a plain KavitaException it surfaces as HTTP 500 with the localized 'SideNav Stream doesn't exist' message via ExceptionMiddleware.","triggerScenarios":"POST /api/streams/update-sidenav-stream with a SideNavStreamDto whose Id does not match any AppUserSideNavStream row (StreamController.UpdateSideNavStream -> StreamService.UpdateSideNavStream). Typical after the stream was deleted server-side or the dto.Id is stale/wrong.","commonSituations":"Toggling visibility from a side-nav list that was not refreshed after another session/device deleted the stream; a malformed client payload sending id: 0 or undefined; concurrent deletion between read and write.","solutions":["Refresh the side-nav list (GET /api/streams/sidenav) and discard local state for any stream whose Id no longer appears before issuing the visibility update.","Validate that dto.Id is a positive integer and exists in the current client-side list before calling.","If the row is gone, remove it from the UI instead of retrying the update."],"exampleFix":"// before\ntoggle(stream: SideNavStreamDto) {\n  return this.http.post('streams/update-sidenav-stream', { ...stream, visible: !stream.visible });\n}\n// after\ntoggle(stream: SideNavStreamDto) {\n  if (!this.currentIds.has(stream.id)) {\n    this.refreshSidenav();\n    return EMPTY;\n  }\n  return this.http.post('streams/update-sidenav-stream', { id: stream.id, visible: !stream.visible });\n}","handlingStrategy":"validation","validationCode":"function canUpdateSideNavStream(currentIds: Set<number>, id: number | undefined): boolean {\n  return typeof id === 'number' && id > 0 && currentIds.has(id);\n}","typeGuard":"function isExistingSideNavStreamId(s: unknown, ids: Set<number>): s is number {\n  return typeof s === 'number' && ids.has(s);\n}","tryCatchPattern":"// treat a 500 'sidenav-stream-doesnt-exist' as a stale-id signal\ndelete stream from local list, then refresh; do not retry with the same id","preventionTips":["Track the live set of side-nav ids and drop edits for ids that vanish.","Re-fetch the side-nav after a delete on another device before toggling visibility.","Validate the dto.id is a positive integer client-side."],"tags":["sidenav","validation","not-found"],"backgroundTag":null,"analyzedSha":"9c3e5400007f8a0282f7d883f2ad5e71716e514d","analyzedAt":"2026-08-13T19:06:05.897Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}