Kareadita/Kavita · warning · KavitaException

You cannot use the name of a system provided stream

Error message

You cannot use the name of a system provided stream

What it means

Thrown by FilterController.ValidateAndSaveFilterUpsert when the requested name matches (case-insensitive) a system-provided stream name in Defaults.DefaultStreams. Caught and returned as HTTP 400 BadRequest. Note the source comment: DefaultStreams names are localization keys (e.g. 'on-deck'), so collisions are rare in practice.

Source

Thrown at Kavita.Server/Controllers/FilterController.cs:129

            var encodedString = SmartFilterHelper.Encode(dto);
            await ValidateAndSaveFilterUpsert(dto.Name!, encodedString, dto.EntityType);
            return Ok();
        }
        catch (KavitaException ex)
        {
            return BadRequest(ex.Message);
        }
    }

    private async Task ValidateAndSaveFilterUpsert(string filterName, string encodedFilter,  FilterEntityType entityType)
    {
        var user = (await unitOfWork.UserRepository.GetUserByIdAsync(UserId, AppUserIncludes.SmartFilters))!;

        if (string.IsNullOrWhiteSpace(filterName)) throw new KavitaException("Name must be set");
        if (Defaults.DefaultStreams.Any(s => s.Name.Equals(filterName, StringComparison.InvariantCultureIgnoreCase)))
        {
            // NOTE: This checks against localization keys (on-deck), so this case will almost never happen
            throw new KavitaException("You cannot use the name of a system provided stream");
        }

        var existingFilter = user.SmartFilters.FirstOrDefault(s => s.Name.Equals(filterName, StringComparison.InvariantCultureIgnoreCase));
        if (existingFilter != null)
        {
            // Update the filter
            existingFilter.Filter = encodedFilter;
            unitOfWork.AppUserSmartFilterRepository.Update(existingFilter);
        }
        else
        {
            existingFilter = new AppUserSmartFilter()
            {
                Name = filterName,
                Filter = encodedFilter,
                EntityType = entityType
            };
            user.SmartFilters.Add(existingFilter);

View on GitHub (pinned to 9c3e540000)

Solutions

  1. Choose a filter name that does not collide with any Defaults.DefaultStreams name.
  2. On the client, reserve/block the known system stream names in the name input.
  3. If you added a new DefaultStream, expect its key to become a reserved filter name.

Example fix

// before
await ValidateAndSaveFilterUpsert("on-deck", encoded, entityType);

// after
await ValidateAndSaveFilterUpsert("My On-Deck", encoded, entityType);
Defensive patterns

Strategy: validation

Validate before calling

var reserved = Defaults.DefaultStreams.Select(s => s.Name)
    .ToHashSet(StringComparer.OrdinalIgnoreCase);
if (reserved.Contains(name))
    return BadRequest("Name reserved for a system stream");

Type guard

static bool IsReservedStreamName(string name)
    => Defaults.DefaultStreams.Any(s =>
        s.Name.Equals(name, StringComparison.OrdinalIgnoreCase));

Try / catch

try { await ValidateAndSaveFilterUpsert(name, enc, type); }
catch (KavitaException ex) { return BadRequest(ex.Message); }

Prevention

When it happens

Trigger: Naming a smart filter exactly the same as a built-in/default stream name like 'on-deck' (case-insensitive).

Common situations: User picks a name that coincides with a system stream key; localization key reuse. Almost never triggers because system stream names are localization keys rather than display names.

Related errors


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