Kareadita/Kavita · warning · KavitaException

sidenav-stream-doesnt-exist

Error message

sidenav-stream-doesnt-exist

What it means

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.

Source

Thrown at Kavita.Services/StreamService.cs:244

            {
                Host = externalSource.Host,
                Id = externalSource.Id,
                Name = externalSource.Name,
                ApiKey = externalSource.ApiKey
            }
        };


        await eventHub.SendMessageToAsync(MessageFactory.SideNavUpdate, MessageFactory.SideNavUpdateEvent(userId),
            userId, ct);
        return ret;
    }

    public async Task UpdateSideNavStream(int userId, SideNavStreamDto dto, CancellationToken ct = default)
    {
        var stream = await unitOfWork.UserRepository.GetSideNavStream(dto.Id, ct);
        if (stream == null)
            throw new KavitaException(await localizationService.TranslateAsync(userId, "sidenav-stream-doesnt-exist"));

        stream.Visible = dto.Visible;

        unitOfWork.UserRepository.Update(stream);
        await unitOfWork.CommitAsync(ct);
        await eventHub.SendMessageToAsync(MessageFactory.SideNavUpdate, MessageFactory.SideNavUpdateEvent(userId),
            userId, ct);
    }

    public async Task UpdateSideNavStreamPosition(int userId, UpdateStreamPositionDto dto, CancellationToken ct = default)
    {
        var user = await unitOfWork.UserRepository.GetUserByIdAsync(userId,
            AppUserIncludes.SideNavStreams, ct);
        var stream = user?.SideNavStreams.FirstOrDefault(d => d.Id == dto.Id);
        if (stream == null) throw new KavitaException(await localizationService.TranslateAsync(userId, "sidenav-stream-doesnt-exist"));

        if (stream.Order == dto.ToPosition) return;

View on GitHub (pinned to 9c3e540000)

Solutions

  1. 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.
  2. Validate that dto.Id is a positive integer and exists in the current client-side list before calling.
  3. If the row is gone, remove it from the UI instead of retrying the update.

Example fix

// before
toggle(stream: SideNavStreamDto) {
  return this.http.post('streams/update-sidenav-stream', { ...stream, visible: !stream.visible });
}
// after
toggle(stream: SideNavStreamDto) {
  if (!this.currentIds.has(stream.id)) {
    this.refreshSidenav();
    return EMPTY;
  }
  return this.http.post('streams/update-sidenav-stream', { id: stream.id, visible: !stream.visible });
}
Defensive patterns

Strategy: validation

Validate before calling

function canUpdateSideNavStream(currentIds: Set<number>, id: number | undefined): boolean {
  return typeof id === 'number' && id > 0 && currentIds.has(id);
}

Type guard

function isExistingSideNavStreamId(s: unknown, ids: Set<number>): s is number {
  return typeof s === 'number' && ids.has(s);
}

Try / catch

// treat a 500 'sidenav-stream-doesnt-exist' as a stale-id signal
delete stream from local list, then refresh; do not retry with the same id

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of Kareadita/Kavita@9c3e540000 (2026-08-13). Data as JSON: /api/errors/e6224515294dde7b. Report an issue: GitHub.