jackwener/OpenCLI · error · CommandExecutionError

juejin recommend returned has_more without a next cursor

Error message

juejin recommend returned has_more without a next cursor

What it means

When the Juejin recommend API says has_more is true (more pages exist) but provides no usable next cursor, the CLI throws a CommandExecutionError because continuing pagination would be impossible. This is an internal-consistency check on the API response: the two fields must agree.

Source

Thrown at clis/juejin/recommend.js:53

        { name: 'cursor', type: 'string', default: '0', help: 'Pagination cursor; pass back the previous response\'s next-page cursor to keep scrolling.' },
    ],
    columns: ['rank', 'article_id', 'title', 'brief', 'views', 'likes', 'comments', 'author', 'tags', 'url', 'next_cursor', 'has_more'],
    func: async (args) => {
        const limit = requireBoundedInt(args.limit, 20, 100);
        const cursor = requireCursor(args.cursor);
        const payload = await juejinFetch(
            '/recommend_api/v1/article/recommend_all_feed',
            { id_type: 2, client_type: 2608, sort_type: 200, limit, cursor },
            'juejin recommend',
        );
        const data = readDataArray(payload, 'juejin recommend');
        const nextCursor = readResponseCursor(payload.cursor);
        if (payload.has_more != null && typeof payload.has_more !== 'boolean') {
            throw new CommandExecutionError('juejin recommend returned a malformed has_more flag');
        }
        const hasMore = payload.has_more == null ? '' : String(payload.has_more);
        if (payload.has_more === true && !nextCursor) {
            throw new CommandExecutionError('juejin recommend returned has_more without a next cursor');
        }
        return data.slice(0, limit).map((row, i) => ({
            ...mapFeedItem(row, i + 1),
            next_cursor: nextCursor,
            has_more: hasMore,
        }));
    },
});

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Retry the request; if the API consistently omits the cursor, treat it as an upstream bug.
  2. Work around by keeping the last known cursor or by raising --limit so fewer pages are needed.
  3. Check whether the API changed pagination semantics and update the CLI accordingly.
  4. Report to the Juejin/CLI maintainers with the raw response payload.

Example fix

// before (hard failure on inconsistency)
if (payload.has_more === true && !nextCursor) {
    throw new CommandExecutionError('juejin recommend returned has_more without a next cursor');
}
// after (degrade gracefully)
const hasMore = payload.has_more === true && nextCursor;
Defensive patterns

Strategy: fallback

Validate before calling

if (payload.has_more === true && !(payload.cursor != null && payload.cursor !== '')) { /* inconsistent page — stop paginating */ }

Type guard

function canContinue(p){ const c = p.cursor; return p.has_more === true && c != null && c !== ''; }

Try / catch

try {
  return cliRecommend({ limit, cursor });
} catch (e) {
  if (/has_more without a next cursor/.test(e.message)) return { items: lastPage.items, has_more: false };
  throw e;
}

Prevention

When it happens

Trigger: A recommend response where payload.has_more === true while payload.cursor is empty, null, undefined, or '' (readResponseCursor returns '' for those).

Common situations: Juejin backend bug where the final-but-nonempty page still sets has_more true without a cursor; hitting a rate-limited or degraded API variant that truncates fields; stale cached responses with missing cursor fields.

Related errors


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