REST /v1/objects totalResults reports the page size, not the total, contradicting the OpenAPI spec
Summary
GET /v1/objects sets totalResults to the number of objects in the page it just returned, so it is always equal to limit (or to the number of remaining objects on the last page). The OpenAPI spec promises the opposite.
openapi-specs/schema.json:3494:
totalResults: "The total number of objects for the query. The number of items in a response may be smaller due to paging."
adapters/handlers/rest/handlers_objects.go, both response sites:
// :279 (list path)
TotalResults: int64(len(list)),
// :340 (query path)
TotalResults: int64(len(resultSet)),len(list) is the page. The spec's own sentence — "the number of items in a response may be smaller due to paging" — only makes sense if totalResults is something other than that number, and it never is.
Reproduction
Any collection with more objects than the limit. Against a 318-object collection:
GET /v1/objects?class=FirstJobsVector&limit=1 -> totalResults=1
GET /v1/objects?class=FirstJobsVector&limit=5 -> totalResults=5
GET /v1/objects?class=FirstJobsVector&limit=100 -> totalResults=100Expected per the spec: 318 in all three cases.
Verified on 1.39.4 (WCD, europe-west3). The code is unchanged on main, and git log -S shows no recent change to either line, so this is long-standing rather than a regression.
Why it matters
The field is the only pagination total the REST object API offers, and it is unusable for that — silently. It never errors, and the value always looks plausible, so a client computing page counts or a sampling offset from it gets a wrong answer that looks right.
Concretely, this bit our own SRE tooling. A vector-index repair verifier sampled objects from a random offset to avoid always probing the same objects:
total, _ := cl.CountObjects(ctx, collection, tenant) // reads totalResults
offset := 0
if int(total) > sampleSize { // always false: total == 1
offset = rand.Intn(int(total) - sampleSize)
}total was always 1, so offset was always 0, and the verifier probed the same head of the collection on every run — the precise failure its own comment said the offset existed to prevent. It went unnoticed because the unit test stubbed the HTTP response with "totalResults":4321 and so never exercised the real semantics.
Any client doing pagination arithmetic off this field has the same latent bug.
Possible resolutions
Listed for discussion, not as a preference — the cost/compat trade-off is the owning team's call.
- Make it the real total. Matches the spec. For the class-scoped path the per-shard object counts Weaviate already maintains (used by
/v1/nodes?output=verboseand by AggregateobjectsCount) should make this cheap; the unfiltered cross-class listing is the harder case. This is a behavior change for anyone relying on today's value. - Correct the spec to describe what the code does. Zero risk, but leaves REST pagination with no total at all — clients just find out sooner.
- Deprecate the field, keep emitting the page length for compatibility, and point clients at Aggregate
objectsCount.
Workaround
For anyone hitting this now: the gRPC Aggregate RPC with objects_count: true returns a correct, tenant-aware count. That is what we moved our tooling to (weaviate/wcs-workflow#917) rather than waiting on a fix here.
Source: weaviate/weaviate