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

  1. Re-run the search to rule out transient cache/proxy staleness
  2. Check whether a proxy/cache is stripping cursor or offset query parameters
  3. Update normalizeSearchUrl so it preserves pagination parameters
  4. 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

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


AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29). Data as JSON: /api/errors/6856271687a846fe. Report an issue: GitHub.