jackwener/OpenCLI · error · CommandExecutionError
Zhihu search pagination returned a repeated next URL
Error message
Zhihu search pagination returned a repeated next URL
What it means
The search pager tracks every followed next URL in a `visited` set. If Zhihu's API returns a paging.next URL that was already followed, the CLI throws to prevent an infinite pagination loop (repeatedly fetching the same page). This detects buggy or wrapped pagination responses.
Source
Thrown at clis/zhihu/search.js:179
for (const item of data.data) {
const rawType = item?.object?.type;
if (type !== 'all' && rawType && rawType !== type) continue;
const normalized = normalizeResultItem(item);
if (!normalized) continue;
if (type !== 'all' && normalized.row.type !== type) continue;
if (seen.has(normalized.key)) continue;
seen.add(normalized.key);
results.push(normalized.row);
if (results.length >= resultLimit) break;
}
if (results.length >= resultLimit) break;
if (data.paging?.is_end) break;
const next = normalizeSearchUrl(data.paging?.next);
if (!next) {
throw new CommandExecutionError('Zhihu search pagination returned malformed next URL');
}
if (visited.has(next)) {
throw new CommandExecutionError('Zhihu search pagination returned a repeated next URL');
}
url = next;
}
if (results.length === 0) {
throw new EmptyResultError('zhihu search', `No ${type === 'all' ? '' : `${type} `}results found for "${query}"`);
}
return results.map((row, i) => {
return {
rank: i + 1,
...row,
};
});
},
});
export const __test__ = {
stripHtml,
itemKey,View on GitHub (pinned to 49907e53dc)
Solutions
- Re-run the search to rule out transient cache/proxy staleness
- Check whether a proxy/cache is stripping cursor or offset query parameters
- Update normalizeSearchUrl so it preserves pagination parameters
- Lower resultLimit to end pagination before the loop point
Defensive patterns
Strategy: validation
Validate before calling
const seen = new Set();
let probe = data.paging?.next && new URL(data.paging.next);
if (probe && seen.has(probe.href)) throw new Error('pagination would loop');
seen.add(probe.href); Type guard
function isFreshNext(next, visited) {
return typeof next === 'string' && !visited.has(next);
} Try / catch
try {
const results = await zhihuSearch(query, opts);
} catch (err) {
if (err.message.includes('repeated next URL')) {
console.error('Zhihu pagination is looping (cache/proxy stripping cursor params); dedupe results manually');
} else throw err;
} Prevention
- Ensure proxies/caches do not strip cursor or offset query parameters
- Keep normalizeSearchUrl from discarding distinguishing pagination params
- Dedupe by item key, not only by URL, when merging pages
- Set a hard max-page bound as a loop backstop
When it happens
Trigger: paging.next points back to a previously fetched page (same normalized URL), e.g. the API ignores the offset/cursor parameter, or a proxy strips query parameters so every next link normalizes to the same URL.
Common situations: Caching layer or corporate proxy serving stale pages, Zhihu cursor parameter ignored under rate limiting, normalizeSearchUrl stripping a distinguishing query param after a change in the URL format.
Related errors
- Zhihu search pagination returned malformed next URL
- tieba search currently only supports --page ${MAX_SUPPORTED_
- Twitter followers pagination repeated a cursor without retur
- WeRead in-book search returned non-advancing searchIdx
- WeRead in-book search returned malformed pagination state
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/6856271687a846fe.
Report an issue: GitHub.