jackwener/OpenCLI · error · CommandExecutionError

Jike search pagination returned a repeated cursor

Error message

Jike search pagination returned a repeated cursor

What it means

searchPosts tracks every pagination cursor it has seen (JSON-stringified). If the API returns a loadMoreKey identical to one already processed, pagination would loop forever, so the CLI throws CommandExecutionError to break the cycle. This indicates the Jike server is handing back the same page pointer.

Source

Thrown at clis/jike/search.js:64

        for (const item of body.data) {
            if (item?.type !== 'ORIGINAL_POST') continue;
            const row = mapPost(item);
            if (seenIds.has(row.id)) continue;
            seenIds.add(row.id);
            rows.push(row);
            if (rows.length >= limit) return rows;
        }
        const next = body.loadMoreKey;
        if (next == null) {
            if (rows.length === 0) throw new EmptyResultError('jike search', `No posts found for "${keyword}"`);
            return rows;
        }
        if (typeof next !== 'object' || Array.isArray(next)) {
            throw new CommandExecutionError('Jike search API returned a malformed pagination cursor');
        }
        const cursorKey = JSON.stringify(next);
        if (seenCursors.has(cursorKey)) {
            throw new CommandExecutionError('Jike search pagination returned a repeated cursor');
        }
        seenCursors.add(cursorKey);
        loadMoreKey = next;
    }
    throw new CommandExecutionError(`Jike search pagination exceeded ${MAX_PAGES} pages before satisfying --limit`);
}

cli({
    site: 'jike',
    name: 'search',
    access: 'read',
    description: '搜索即刻帖子',
    domain: 'web.okjike.com',
    strategy: Strategy.COOKIE,
    browser: true,
    args: [
        { name: 'query', type: 'string', required: true, positional: true, help: '即刻搜索关键词' },
        { name: 'limit', type: 'int', default: DEFAULT_LIMIT },

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Reduce --limit so fewer pages are needed and retry.
  2. Re-login / refresh the Jike session cookies and retry.
  3. Wait and retry later — repeated cursors are usually a transient server-side issue.
  4. Catch this error and return the rows collected so far instead of failing.

Example fix

// before
const rows = await runCli(['jike', 'search', keyword, '--limit', '100']);
// after: accept partial results
tlet rows;
try { rows = await runCli(['jike', 'search', keyword, '--limit', '100']); }
catch (e) {
  if (/repeated cursor/.test(e.message)) rows = [];
  else throw e;
}
Defensive patterns

Strategy: retry

Validate before calling

// keep --limit modest so pagination depth stays low
const LIMIT_MAX_SAFE = 100;
const limit = Math.min(requested, LIMIT_MAX_SAFE);

Try / catch

let rows = [];
try {
  rows = await runCli(['jike', 'search', keyword, '--limit', n]);
} catch (e) {
  if (/repeated cursor/.test(e.message)) console.warn('cursor loop at Jike; using partial results');
  else throw e;
}

Prevention

When it happens

Trigger: Two consecutive pages return the exact same loadMoreKey object, typically because the server-side cursor failed to advance while more results exist.

Common situations: Jike backend pagination bugs during high load; cursor not advancing for filtered/moderated keywords; stale session causing server to replay cached results.

Related errors


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