{"record":{"id":"775f2ba97cc70af2","repo":"Kareadita/Kavita","slug":"external-source-doesnt-exist","errorCode":null,"errorMessage":"external-source-doesnt-exist","messagePattern":"external-source-doesnt-exist","errorType":"exception","errorClass":"KavitaException","httpStatus":400,"severity":"warning","filePath":"Kavita.Services/StreamService.cs","lineNumber":198,"sourceCode":"            Order = createdStream.Order,\n            SmartFilterEncoded = smartFilter.Filter,\n            StreamType = createdStream.StreamType\n        };\n\n\n        await eventHub.SendMessageToAsync(MessageFactory.SideNavUpdate, MessageFactory.SideNavUpdateEvent(userId),\n            userId, ct);\n        return ret;\n    }\n\n    public async Task<SideNavStreamDto> CreateSideNavStreamFromExternalSource(int userId, int externalSourceId,\n        CancellationToken ct = default)\n    {\n        var user = await unitOfWork.UserRepository.GetUserByIdAsync(userId, AppUserIncludes.SideNavStreams, ct);\n        if (user == null) throw new KavitaException(await localizationService.TranslateAsync(userId, \"no-user\"));\n\n        var externalSource = await unitOfWork.AppUserExternalSourceRepository.GetById(externalSourceId, ct);\n        if (externalSource == null) throw new KavitaException(await localizationService.TranslateAsync(userId, \"external-source-doesnt-exist\"));\n\n        var stream = user?.SideNavStreams.FirstOrDefault(d => d.ExternalSourceId == externalSourceId);\n        if (stream != null) throw new KavitaException(await localizationService.TranslateAsync(userId, \"external-source-already-in-use\"));\n\n        var maxOrder = user!.SideNavStreams.Max(d => d.Order);\n        var createdStream = new AppUserSideNavStream()\n        {\n            Name = externalSource.Name,\n            IsProvided = false,\n            StreamType = SideNavStreamType.ExternalSource,\n            Visible = true,\n            Order = maxOrder + 1,\n            ExternalSourceId = externalSource.Id\n        };\n\n        user.SideNavStreams.Add(createdStream);\n        unitOfWork.UserRepository.Update(user);\n        await unitOfWork.CommitAsync(ct);","sourceCodeStart":180,"sourceCodeEnd":216,"githubUrl":"https://github.com/Kareadita/Kavita/blob/9c3e5400007f8a0282f7d883f2ad5e71716e514d/Kavita.Services/StreamService.cs#L180-L216","documentation":"Thrown by StreamService.CreateSideNavStreamFromExternalSource when AppUserExternalSourceRepository.GetById(externalSourceId) returns null — the external source does not exist (or does not belong to the user). The message is translated to 'External Source doesn't exist'. StreamController.AddSideNavFromExternalSource does not catch KavitaException, so it surfaces as HTTP 500 via ExceptionMiddleware.","triggerScenarios":"POST /api/stream/add-sidenav-stream-from-external-source?externalSourceId=N with a deleted, invalid, or other-user external source id.","commonSituations":"Stale externalSourceId cached in the UI after the source was deleted; deep link with an old id; cross-user id confusion.","solutions":["Use an externalSourceId from the user's current external sources (GET /api/stream/external-sources).","Refresh the external sources list before offering 'add to side nav'.","Recreate the external source if it was deleted, then add the side-nav stream."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"const sources = await api.get('/api/stream/external-sources');\nif (!sources.some(s => s.id === externalSourceId)) {\n  showError('External Source not found');\n  return;\n}\nawait api.post(`/api/stream/add-sidenav-stream-from-external-source?externalSourceId=${externalSourceId}`);","typeGuard":"function isKnownExternalSourceId(id: number, sources: { id: number }[]): boolean {\n  return sources.some(s => s.id === id);\n}","tryCatchPattern":null,"preventionTips":["Offer 'add to side nav' only for external sources in the user's current list.","Refresh external sources after delete operations.","Validate deep-link ids before calling."],"tags":["external-source","stream","sidenav","validation","not-found"],"backgroundTag":null,"analyzedSha":"9c3e5400007f8a0282f7d883f2ad5e71716e514d","analyzedAt":"2026-08-13T19:06:05.897Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}