Kareadita/Kavita · warning · KavitaNotFoundException

series-restricted-age-restriction

series-restricted-age-restriction

Error message

series-restricted-age-restriction

What it means

Thrown as KavitaNotFoundException with the localized 'series-restricted-age-restriction' key by SeriesController's external-series-detail endpoint when the computed effective age rating of the external series exceeds the requesting user's AgeRestriction (RecommendationHelper.IsWithinAgeRestriction returns false). ExceptionMiddleware maps KavitaNotFoundException to HTTP 404 NotFound with no body.

Source

Thrown at Kavita.Server/Controllers/SeriesController.cs:630

                return BadRequest(await localizationService.TranslateAsync("generic-error"));
            }
        }

        if (ret == null) return BadRequest(await localizationService.TranslateAsync("generic-error"));

        var user = await unitOfWork.UserRepository.GetUserByIdAsync(UserId, ct: ct);
        var restriction = new Models.Entities.AgeRestriction
        {
            AgeRating = user?.AgeRestriction ?? AgeRating.NotApplicable,
            IncludeUnknowns = user?.AgeRestrictionIncludeUnknowns ?? true
        };
        var settings = await unitOfWork.SettingsRepository.GetMetadataSettingDto(ct);
        var effectiveRating = RecommendationHelper.ComputeExternalAgeRating(ret.AgeRating,
            ret.Genres ?? [], (ret.Tags ?? []).Select(t => t.Name), settings);

        if (!RecommendationHelper.IsWithinAgeRestriction(effectiveRating, restriction))
        {
            throw new KavitaNotFoundException(await localizationService.TranslateAsync("series-restricted-age-restriction"));
        }

        return Ok(ret);
    }

    /// <summary>
    /// Based on the delta times between when chapters are added, for series that are not Completed/Cancelled/Hiatus, forecast the next
    /// date when it will be available.
    /// </summary>
    /// <param name="seriesId"></param>
    /// <returns></returns>
    [SeriesAccess]
    [HttpGet("next-expected")]
    public async Task<ActionResult<NextExpectedChapterDto>> GetNextExpectedChapter(int seriesId)
    {
        var userId = UserId;
        var ct = HttpContext.RequestAborted;

View on GitHub (pinned to 9c3e540000)

Solutions

  1. Have an admin raise (or remove) the user's AgeRestriction if the content is appropriate.
  2. Accept the restriction — this is intended behavior protecting age-limited users.
  3. Review the series tags/genres if a clearly-safe series is being over-rated.
Defensive patterns

Strategy: validation

Validate before calling

var restriction = new AgeRestriction {
    AgeRating = user?.AgeRestriction ?? AgeRating.NotApplicable,
    IncludeUnknowns = user?.AgeRestrictionIncludeUnknowns ?? true };
if (!RecommendationHelper.IsWithinAgeRestriction(effectiveRating, restriction))
    return NotFound();

Try / catch

try { return Ok(await GetSeriesDetail(...)); }
catch (KavitaNotFoundException) { return NotFound(); }

Prevention

When it happens

Trigger: A user with an age restriction (e.g. restricted to Teen) requests external series detail (AniList/MAL/MangaBaka) for a series whose effective rating is above their limit. The effective rating is computed from the series rating plus its genres/tags via RecommendationHelper.ComputeExternalAgeRating.

Common situations: A restricted (child/age-limited) account browses to a mature series recommendation; metadata settings inflate the effective rating; tags/genres push a borderline series above the threshold.

Related errors


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