Skip to content

fix(storage): send camelCase pagination keys in list_indexes - #1633

Open
hsusul wants to merge 1 commit into
supabase:mainfrom
hsusul:fix/storage-vectors-list-indexes-pagination
Open

hsusul wants to merge 1 commit into
supabase:mainfrom
hsusul:fix/storage-vectors-list-indexes-pagination

Conversation

@hsusul

@hsusul hsusul commented Sep 10, 2026

Copy link
Copy Markdown
Contributor

What kind of change does this PR introduce?

Bug fix.

What is the current behavior?

Fixes #1632

VectorBucketScope.list_indexes() builds its request body with snake_case keys:

body = self.with_metadata(
    next_token=next_token, max_results=max_results, prefix=prefix
)

The Storage /vector/ListIndexes endpoint only reads maxResults and nextToken (schema), and it ignores unknown properties, so both values are silently dropped:

  • max_results has no effect; the page size is always the server default (500).
  • next_token has no effect, so asking for the next page returns the first page again. The usual while page.nextToken: loop over ListVectorIndexesResponse.nextToken — the SDK's own response field — never terminates once a bucket has more than one page of indexes.

prefix happens to be spelled the same in both conventions, which is why it works.

What is the new behavior?

The body uses the wire names nextToken / maxResults, matching every other vector request in the module (list_buckets(), VectorIndexScope.list()) and the camelCase response model. The Python keyword arguments are unchanged, so this is not an API change.

The async client and its generated sync twin had the same line; both are updated. I confirmed the sync edit is exactly what run-unasync.py generates from the async fix (differing only in line wrapping that ruff format settles), and kept the diff to that single line rather than committing the unrelated regeneration churn.

Tests

test_async_list_indexes_sends_camel_case_pagination and test_sync_list_indexes_sends_camel_case_pagination in src/storage/tests/test_client.py drive list_indexes() through a real client over an httpx.MockTransport and assert the exact JSON body sent to /vector/ListIndexes. Both fail on main (body has next_token / max_results) and pass here. There was no prior test coverage for the vectors client.

Validation

  • uv run --package storage3 pytest tests/test_client.py tests/test_utils.py tests/test_exceptions.py — 32 passed.
  • uv run --package storage3 --group mypy mypy src/storage3 tests — success, 33 source files.
  • uv run ruff check --fix / uv run ruff format — clean.
  • git diff --check — clean.

tests/_async and tests/_sync are integration tests that need the storage stack from make storage.start-infra (Docker + Supabase CLI), which was not running here. They error with httpx.ConnectError — 50 errors both on main and with this change (66 → 68 passed, the difference being the two new tests).

Additional context

None.

VectorBucketScope.list_indexes sent next_token and max_results as
snake_case body keys. The /vector/ListIndexes endpoint only reads
nextToken and maxResults and ignores unknown properties, so both values
were silently dropped: the page size was always the server default and
a next_token request returned the first page again, making the usual
pagination loop never terminate.

Use the wire names, as every other vector request in the module already
does. Applies to the async client and its generated sync twin.

Fixes supabase#1632
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

storage3 vectors list_indexes() drops next_token and max_results

1 participant