{"record":{"id":"0e0028d543edcc01","repo":"Kareadita/Kavita","slug":"opds-feed-generation-is-not-implemented-for-person","errorCode":null,"errorMessage":"OPDS feed generation is not implemented for Person smart filters","messagePattern":"OPDS feed generation is not implemented for Person smart filters","errorType":"exception","errorClass":"OpdsException","httpStatus":null,"severity":"error","filePath":"Kavita.Services/OpdsService.cs","lineNumber":426,"sourceCode":"                    (SeriesFilterV2Dto) decodedFilter, ct: ct);\n                var seriesMetadatas = await unitOfWork.SeriesRepository.GetSeriesMetadataForIdsAsync(series.Select(s => s.Id), ct);\n\n                foreach (var seriesDto in series)\n                {\n                    feed.Entries.Add(CreateSeries(seriesDto, seriesMetadatas.First(s => s.SeriesId == seriesDto.Id), apiKey, prefix, baseUrl));\n                }\n                AddPagination(feed, series, $\"{prefix}{apiKey}/smart-filters/{request.EntityId}/\");\n                break;\n            case FilterEntityType.ReadingList:\n                var readingLists = await unitOfWork.ReadingListRepository.GetBrowseReadingListDtos(userId, (ReadingListFilterDto) decodedFilter, userParams, ct);\n                foreach (var readingList in readingLists)\n                {\n                    feed.Entries.Add(CreateReadingListFeedEntry(readingList, prefix, apiKey, baseUrl));\n                }\n                AddPagination(feed, readingLists, $\"{prefix}{apiKey}/smart-filters/{request.EntityId}/\");\n                break;\n            case FilterEntityType.Person:\n                throw new OpdsException(\"OPDS feed generation is not implemented for Person smart filters\");\n            case FilterEntityType.Annotation:\n                throw new OpdsException(\"OPDS feed generation is not implemented for Annotation smart filters\");\n        }\n\n        return feed;\n    }\n\n    public async Task<Feed> GetSeriesFromCollection(OpdsItemsFromEntityIdRequest request, CancellationToken ct = default)\n    {\n        var userId = UnpackRequest(request, out var apiKey, out var prefix, out var baseUrl);\n        var collectionId = request.EntityId;\n\n        var tag = await unitOfWork.CollectionTagRepository.GetCollectionAsync(collectionId, ct: ct);\n        if (tag == null || (tag.AppUserId != userId && !tag.Promoted))\n        {\n            throw new OpdsException(await localizationService.TranslateAsync(userId, \"collection-doesnt-exist\"));\n        }\n","sourceCodeStart":408,"sourceCodeEnd":444,"githubUrl":"https://github.com/Kareadita/Kavita/blob/9c3e5400007f8a0282f7d883f2ad5e71716e514d/Kavita.Services/OpdsService.cs#L408-L444","documentation":"Thrown by OpdsService.ResolveSmartFilter when the decoded smart filter has FilterEntityType.Person. The OPDS feed generation switch statement only handles Series and ReadingList entity types; Person is an explicit unimplemented branch that throws immediately. This is a known feature gap: Kavita's smart filter engine supports Person-based filters internally, but the OPDS catalog feed builder has no rendering path for them.","triggerScenarios":"A user creates a Person-type smart filter in the Kavita web UI (filtering by writer, artist, character, etc.). They then attempt to open that filter's feed via an OPDS reader at {apiKey}/smart-filters/{filterId}. SmartFilterHelper.Decode identifies the EntityType as Person, and the switch falls into the throw branch.","commonSituations":"A user has Person-type smart filters alongside their Series/ReadingList filters, and their OPDS reader auto-crawls all filter feeds. The OPDS reader cached a link to a Person filter before OPDS Person-feed support existed (it still doesn't).","solutions":["Avoid accessing Person-type smart filters through the OPDS feed; use the Kavita web UI instead, where Person filters are fully supported.","Recreate the filter as a Series-type filter that filters by Person attributes, which will render correctly in OPDS.","Request the feature from Kavita's issue tracker if Person OPDS feeds are needed.","In the OPDS client, hide or exclude Person-type filters from the smart-filter listing to prevent users from navigating into them.","If building a custom OPDS integration, check the filter's EntityType via the API before requesting the feed and gracefully skip Person types."],"exampleFix":"// If you control the OPDS client, skip Person/Annotation filters:\n// Before calling ResolveSmartFilter, check the filter type:\n\n// GET /api/opds/{apiKey}/smart-filters/{filterId}  (metadata)\n// if filter.EntityType == 'Person': skip with a user-friendly message\n\n// Alternatively, recreate the filter targeting Series with a Person condition:\n// SmartFilter { EntityType: Series, Statements: [{ Field: Writers, Value: 'Name' }] }","handlingStrategy":"validation","validationCode":"// Before requesting a Person-type smart filter feed, check the EntityType:\n// var filter = await unitOfWork.AppUserSmartFilterRepository.GetById(filterId, ct);\n// if (filter == null) return NotFound();\n// var decoded = SmartFilterHelper.Decode(filter.Filter);\n// if (decoded.EntityType == FilterEntityType.Person)\n// {\n//     return BadRequest(\"Person smart filters are not available in OPDS.\");\n// }\n// var feed = await opdsService.ResolveSmartFilter(request, ct);","typeGuard":"// C# type/enum guard for the filter entity type:\nstatic bool IsOpdsSupportedFilterType(FilterEntityType type)\n    => type is FilterEntityType.Series or FilterEntityType.ReadingList;","tryCatchPattern":"// try { var feed = await opdsService.ResolveSmartFilter(request, ct); }\n// catch (OpdsException ex) when (ex.Message.Contains(\"not implemented\"))\n// {\n//     // This filter type is not supported in OPDS.\n//     // Show a user-friendly message; do not retry.\n//     return BadRequest(\"This smart filter type is not supported in OPDS feeds.\");\n// }","preventionTips":["Do not create Person-type smart filters if OPDS access is expected; use Series-type filters instead.","In OPDS clients, filter the smart-filter listing to exclude Person and Annotation types.","Educate users that only Series and ReadingList smart filters are OPDS-accessible.","When building OPDS integrations, check EntityType before requesting the feed.","File a feature request if Person OPDS feed support is needed."],"tags":["opds","smart-filter","unimplemented","person","feed","feature-gap"],"backgroundTag":null,"analyzedSha":"9c3e5400007f8a0282f7d883f2ad5e71716e514d","analyzedAt":"2026-08-13T19:06:05.897Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}