| Fix | Title | Endpoints | Fields |
| F1 | invite response is an object, not a string | /api/Account/invite (post) | — |
| F2 | nullable enum fields | — | SeriesDto.metadataProviderOverride, ChapterDto.format, MetadataSettingsDto.filterAboveWeight, TachiyomiChapterDto.format |
| F3 | bare (non-JSON) string response bodies | /api/Health (get), /api/Account/invite-url (get), /api/Upload/upload-by-file (post), /api/Account/opds-url (get), /api/Settings/base-url (get), /api/Metadata/language-title (get), /api/Series/age-rating (get), /api/Account/forgot-password (post) | — |
| F4 | info.version one step behind the release tag | — | — |
| F5 | file-breakdown response is one object, not an array | /api/Stats/server/file-breakdown (get) | — |
| F6 | series-detail-plus nullable object refs | /api/Metadata/series-detail-plus (get) | SeriesDetailPlusDto.recommendations, SeriesDetailPlusDto.series |
| F7 | Annotation/all-for-series response is a list, not one object | /api/Annotation/all-for-series (get) | — |
| F8 | prompt-reread responses may be null | /api/Reader/prompt-reread/chapter (get), /api/Reader/prompt-reread/series (get), /api/Reader/prompt-reread/volume (get) | — |
| F9 | nullable object refs found by the canary | — | RereadDto.chapterOnContinue, RereadDto.chapterOnReread, SideNavStreamDto.externalSource, SideNavStreamDto.library |
| F10 | Stats/device/device-type response is a list, not one object | /api/Stats/device/device-type (get) | — |
| Id | Category | Status | Title | Fix |
Endpoints | covered_by | Note |
| Q01 | fix-dependent | open | invite returns an object where the spec declares a string | F1 | 1 | tests/integration/test_invite.py | The three media types all declare {type: string}; the server sends InviteUserResponse. Upstream issue Kareadita/Kavita#4934 covers this class. |
| Q02 | fix-dependent | open | nullable enum fields declared non-nullable | F2 | 3 | tests/integration/test_media.py, tests/integration/test_sweep.py, tests/integration/test_small_families.py | Endpoint list covers the curated ops whose responses carry the nullable DTOs; the Schemathesis prototype triage may extend it. |
| Q03 | fix-dependent | open | bare text bodies where JSON-ish media types are declared | F3 | 0 | tests/integration/test_auth.py, tests/integration/test_invite.py, tests/integration/test_media.py, tests/integration/test_sweep.py, tests/integration/test_email.py | No exclusion: the raw spec declares text/plain + string schema and the server sends exactly that, so Schemathesis validates fine (the JSON crash was client-side only). |
| Q05 | fix-dependent | open | file-breakdown returns an object where the spec declares an array | F5 | 1 | tests/integration/test_sweep.py | |
| Q06 | fix-dependent | open | series-detail-plus sends null for non-nullable object refs | F6 | 1 | tests/integration/test_metadata_extra.py | |
| Q24 | fix-dependent | open | Annotation/all-for-series returns a list where the spec declares one object | F7 | 1 | tests/integration/test_metadata_extra.py::test_annotation_all_for_series | Found by the Schemathesis prototype (2026-09-21): the controller declares ActionResult<AnnotationDto> but returns List<AnnotationDto> (GetAnnotationDtosBySeries). |
| Q25 | fix-dependent | open | prompt-reread endpoints return null where the spec declares RereadDto | F8 | 3 | tests/integration/test_reader.py::test_prompt_reread | Found by the Schemathesis prototype (2026-09-21): the reread checks return null (no reread due) where the spec declares a non-nullable RereadDto. |
| Q30 | fix-dependent | open | RereadDto chapter refs are null in real responses | F9 | 0 | tests/integration/test_reader.py::test_prompt_reread | Found by the canary (2026-09-21): the non-null body case carries chapterOnContinue/chapterOnReread as null. |
| Q31 | fix-dependent | open | Stats/device/device-type returns a list where the spec declares one object | F10 | 1 | tests/integration/test_sweep.py | Found by the canary (2026-09-21): the server returns an array of {count, value}; the spec declares a single StringStatCount. |
| Q32 | fix-dependent | open | Stream/sidenav externalSource is null | F9 | 1 | — | Found by the canary (2026-09-21): SideNavStreamDto.externalSource is null when no external source is attached; the curated suite does not call sidenav yet. |
| Q10a | dead-quirk | open | License/info returns 204 without a license (spec documents 200) | — | 1 | — | |
| Q10b | dead-quirk | open | Plugin/authkey-expires returns 400 (context not in the spec) | — | 1 | — | |
| Q10c | dead-quirk | open | Users/tokens returns 403 (Kavita+ only) | — | 1 | — | |
| Q15a | dead-quirk | open | Series/match-info returns 403 (Kavita+ only) | — | 1 | — | |
| Q18a | dead-quirk | open | Library/delete-multiple returns an empty body (spec declares boolean) | — | 1 | tests/integration/test_mutations.py::test_library_create_and_delete | Upstream issue draft: docs/issue-draft-library-delete-multiple.md. |
| D01 | destructive | open | Settings/reset | — | 1 | tests/integration/test_zz_destructive.py | |
| D02 | destructive | open | Settings POST (random settings would break the rest of the run) | — | 1 | tests/integration/test_email.py | |
| D03 | destructive | open | Server/cleanup | — | 1 | tests/integration/test_zz_destructive.py | |
| D04 | destructive | open | Users/delete-user | — | 1 | tests/integration/test_mutations.py | |
| D05 | destructive | open | Series/delete-multiple | — | 1 | tests/integration/test_zz_destructive.py | |
| D06 | destructive | open | Chapter DELETE (single) | — | 1 | — | |
| D07 | destructive | open | Chapter/delete-multiple | — | 1 | — | |
| D08 | destructive | open | Account/register (first-user-only; random bodies 400) | — | 1 | tests/integration/test_auth.py | |
| Q26 | undocumented-auth | open | endpoints requiring auth where the spec documents none | — | 43 | — | 401/403 on random apiKeys/ids (or Kavita+ gating); the curated suite covers the subset it exercises with real ids/admin client. |
| Q27 | server-error-on-garbage | open | server 500s on garbage input | — | 55 | — | Robustness bugs (not contract drift); candidate for a separate upstream report. |
| Q28 | stateful-id | open | stateful ops that 4xx/204 on generated ids | — | 321 | — | The fresh server has no entities, so schema-valid but random ids land on undocumented statuses. Re-includable via the value-provider registry (phase 2) against the populated fixture. |
| Q29a | schema-mismatch | open | date-time fields carry 7 fractional seconds (.NET ticks) | — | 0 | — | Schema-wide: the server serializes DateTime with 7-digit fractions, but format: date-time (RFC 3339) allows at most 3. Found by the Schemathesis prototype; the runner installs a lenient checker. |
| Q29b | schema-mismatch | open | empty date-times serialized as 0001-01-01T00:00:00 | — | 0 | — | Schema-wide MinValue leak (DateTime.MinValue instead of null); tolerated by the runner's lenient checker. |
| Q08 | resolved | resolved | date-range Stats need a populated library (+ reading-activity year, reading-history tzId) | — | 0 | tests/integration/test_stats_dates.py | |
| Q15b | resolved | resolved | Image library/user covers 404 until a cover is uploaded | — | 0 | tests/integration/test_image.py | |
| Q15c | resolved | resolved | currently-reading empty for fresh reads (flipped ReadLast filter) | — | 0 | tests/integration/test_series_extra.py | |
| Q18b | resolved | resolved | Library/delete false while a scan task runs | — | 0 | tests/integration/test_mutations.py | |
| Q19a | resolved | resolved | OPDS image feed works headlessly (earlier 400 was a bad-id artifact) | — | 0 | tests/integration/test_opds.py | |
| Q19b | resolved | resolved | OPDS favicon needs an .ico mounted in the container | — | 0 | tests/integration/test_opds.py | |
| Q23 | infra | resolved | update-check endpoints call api.github.com (local TLS mock in fixtures) | — | 4 | tests/integration/test_sweep.py | Mock-pinned via the github_mock fixture; deterministic, so no exclusion. |