Skip to content

Apollo OSV API: total echoes the page size, and the after filter returns HTTP 500 #86

Description

@cedricbonhomme

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions