Describe the bug
After V2ListIterator exhausts the current page and calls turnPage(), it
calls .next() on the returned iterator exactly once. If the API returns
a page with data: [] but a non-null next_page_url — which can occur during
server-side cursor races — the single .next() returns {done: true} and the
method immediately returns {done: true, value: undefined}, silently dropping
all items on every subsequent page.
Current code:
const nextPageIterator = await this.turnPage();
if (!nextPageIterator) return {done: true, value: undefined};
const result = nextPageIterator.next();
if (!result.done) return {done: false, value: result.value};
return {done: true, value: undefined}; // gives up if page was empty
To Reproduce
Use a V2 list endpoint. Simulate or encounter a server response where an
intermediate page returns data: [] with next_page_url pointing to a page
that does contain items. Iteration will stop at the empty page and never
reach the items.
Expected behavior
If a page has data: [] but next_page_url is set, the iterator should
continue fetching pages until it finds an item or next_page_url is null.
Code snippets
OS
Not environment-specific — reproduced by code inspection of src/autoPagination.ts. The missing while loop in V2ListIterator.next() will truncate iteration on empty intermediate pages regardless of operating system.
Node version
Reproducible on any supported Node version. Verified against Node 20 LTS. The bug is structural — after turnPage() returns, .next() is called exactly once on the new iterator. If that page is empty, iteration terminates regardless of Node version or runtime environment.
Library version
stripe-node master branch — confirmed in src/autoPagination.ts V2ListIterator.next() method (current master HEAD).
API version
Affects V2 API endpoints only (paths beginning with /v2/). Triggered when the server returns an intermediate page with data: [] and a non-null next_page_url — possible under cursor-race conditions during high-concurrency V2 list requests. Any API version using V2 list endpoints (2025-03-31.basil or later).
Additional context
V1Iterator does not have this problem because it recurses through iterate()
which checks has_more in a loop. V2ListIterator needs the equivalent
while loop pattern.
Related to the concurrency issue filed separately. Both are in V2ListIterator
and can be fixed in a single PR.
Describe the bug
After V2ListIterator exhausts the current page and calls turnPage(), it
calls .next() on the returned iterator exactly once. If the API returns
a page with data: [] but a non-null next_page_url — which can occur during
server-side cursor races — the single .next() returns {done: true} and the
method immediately returns {done: true, value: undefined}, silently dropping
all items on every subsequent page.
Current code:
const nextPageIterator = await this.turnPage();
if (!nextPageIterator) return {done: true, value: undefined};
const result = nextPageIterator.next();
if (!result.done) return {done: false, value: result.value};
return {done: true, value: undefined}; // gives up if page was empty
To Reproduce
Use a V2 list endpoint. Simulate or encounter a server response where an
intermediate page returns data: [] with next_page_url pointing to a page
that does contain items. Iteration will stop at the empty page and never
reach the items.
Expected behavior
If a page has data: [] but next_page_url is set, the iterator should
continue fetching pages until it finds an item or next_page_url is null.
Code snippets
OS
Not environment-specific — reproduced by code inspection of src/autoPagination.ts. The missing while loop in V2ListIterator.next() will truncate iteration on empty intermediate pages regardless of operating system.
Node version
Reproducible on any supported Node version. Verified against Node 20 LTS. The bug is structural — after turnPage() returns, .next() is called exactly once on the new iterator. If that page is empty, iteration terminates regardless of Node version or runtime environment.
Library version
stripe-node master branch — confirmed in src/autoPagination.ts V2ListIterator.next() method (current master HEAD).
API version
Affects V2 API endpoints only (paths beginning with /v2/). Triggered when the server returns an intermediate page with data: [] and a non-null next_page_url — possible under cursor-race conditions during high-concurrency V2 list requests. Any API version using V2 list endpoints (2025-03-31.basil or later).
Additional context
V1Iterator does not have this problem because it recurses through iterate()
which checks has_more in a loop. V2ListIterator needs the equivalent
while loop pattern.
Related to the concurrency issue filed separately. Both are in V2ListIterator
and can be fixed in a single PR.