Apollo OSV API: total echoes the page size, and the after filter returns HTTP 500
Context
We are consuming the Apollo OSV endpoint (https://apollo.build.resf.org/api/v3/osv/) in Vulnerability-Lookup to import Rocky Linux advisories (vulnerability-lookup#482). While integrating it we found two API defects that make standard pagination and incremental fetching impossible. Both were verified against the live instance on 2026-07-20.
1. total echoes the requested page size instead of the record count
$ curl -s 'https://apollo.build.resf.org/api/v3/osv/?page=1&size=2' | jq '{total, page, size, n: (.advisories|length), last: .links.last}'
{
"total": 2,
"page": 1,
"size": 2,
"n": 2,
"last": "/api/v3/osv/?size=2&page=1"
}
$ curl -s 'https://apollo.build.resf.org/api/v3/osv/?page=1&size=3' | jq '.total'
3
Whatever size is requested comes back as total, and links.last always points at page 1 — even though deeper pages exist and return full pages of distinct records:
$ curl -s 'https://apollo.build.resf.org/api/v3/osv/?page=2&size=3' | jq '[.advisories[].id]'
[
"RLSA-2026:39976",
"RLSA-2026:39798",
"RLSA-2026:39771"
]
Any client using the documented pagination metadata (page * size >= total, or following links.last) will stop after the first page and silently miss the rest of the feed. As a workaround we now page until a short page is returned.
Note: the other Apollo v3 list endpoints may share the paginator, so this could affect more than the OSV route.
2. The after parameter returns HTTP 500
The OpenAPI spec declares after (and before) as optional date-time query parameters on /api/v3/osv/, but every well-formed value answers 500 Internal Server Error:
$ curl -s -o /dev/null -w '%{http_code}\n' 'https://apollo.build.resf.org/api/v3/osv/?page=1&size=5&after=2026-07-19T00:00:00Z'
500
$ curl -s -o /dev/null -w '%{http_code}\n' 'https://apollo.build.resf.org/api/v3/osv/?page=1&size=5&after=2026-07-19T00%3A00%3A00%2B00%3A00'
500
$ curl -s -o /dev/null -w '%{http_code}\n' 'https://apollo.build.resf.org/api/v3/osv/?page=1&size=5&after=notadate'
422
The 422 on garbage input shows the parameter is parsed and validated; the 500 happens on the query itself. Without a working after, incremental consumption isn't possible and clients must re-crawl the full feed on every run. The feed is currently small (~490 advisories), so this is tolerable, but it won't scale as the advisory count grows.
Minor observation
While crawling, records can shift between pages mid-walk: a full walk at size=100 returned 497 advisory objects but only 490 unique ids. A stable sort key for pagination (or keyset pagination) would make crawls consistent.
Thanks a lot for Apollo and for publishing these advisories in OSV format — happy to test any fix against our importer.
Apollo OSV API:
totalechoes the page size, and theafterfilter returns HTTP 500Context
We are consuming the Apollo OSV endpoint (
https://apollo.build.resf.org/api/v3/osv/) in Vulnerability-Lookup to import Rocky Linux advisories (vulnerability-lookup#482). While integrating it we found two API defects that make standard pagination and incremental fetching impossible. Both were verified against the live instance on 2026-07-20.1.
totalechoes the requested page size instead of the record countWhatever
sizeis requested comes back astotal, andlinks.lastalways points at page 1 — even though deeper pages exist and return full pages of distinct records:Any client using the documented pagination metadata (
page * size >= total, or followinglinks.last) will stop after the first page and silently miss the rest of the feed. As a workaround we now page until a short page is returned.Note: the other Apollo v3 list endpoints may share the paginator, so this could affect more than the OSV route.
2. The
afterparameter returns HTTP 500The OpenAPI spec declares
after(andbefore) as optionaldate-timequery parameters on/api/v3/osv/, but every well-formed value answers500 Internal Server Error:The 422 on garbage input shows the parameter is parsed and validated; the 500 happens on the query itself. Without a working
after, incremental consumption isn't possible and clients must re-crawl the full feed on every run. The feed is currently small (~490 advisories), so this is tolerable, but it won't scale as the advisory count grows.Minor observation
While crawling, records can shift between pages mid-walk: a full walk at
size=100returned 497 advisory objects but only 490 unique ids. A stable sort key for pagination (or keyset pagination) would make crawls consistent.Thanks a lot for Apollo and for publishing these advisories in OSV format — happy to test any fix against our importer.