jackwener/OpenCLI · error · CommandExecutionError

Zhihu search pagination returned malformed next URL

Error message

Zhihu search pagination returned malformed next URL

What it means

During paginated search, the CLI follows data.paging.next links, normalizing each through normalizeSearchUrl. If the next URL is absent or fails normalization (not a valid/allowed Zhihu search URL), it throws this CommandExecutionError rather than continuing with a broken link. This guards against infinite or invalid pagination states caused by upstream API changes.

Source

Thrown at clis/zhihu/search.js:176

        }
      })()
    `), url);
            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,
            };
        });
    },
});

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Re-run the search; transient API responses may include proper paging next time
  2. Reduce resultLimit so fewer pages are needed
  3. Log data.paging to inspect the raw next value and adjust normalizeSearchUrl
  4. Handle Zhihu auth/rate limiting so paging metadata is returned intact

Example fix

// before
const next = normalizeSearchUrl(data.paging?.next);
if (!next) {
    throw new CommandExecutionError('Zhihu search pagination returned malformed next URL');
}
// after
const next = normalizeSearchUrl(data.paging?.next);
if (!next) {
    if (data.paging?.is_end) break;
    console.warn('stopping pagination: malformed next URL');
    break;
}
Defensive patterns

Strategy: validation

Validate before calling

function hasNextPage(data) {
  const next = data?.paging?.next;
  return typeof next === 'string' && next.startsWith('https://www.zhihu.com/') && next !== '';
}
if (data.paging?.is_end !== true && !hasNextPage(data)) throw new Error('unexpected paging state');

Type guard

function isValidPagingNext(paging) {
  return typeof paging?.next === 'string' &&
    paging.next.length > 0 &&
    URL.canParse(paging.next) &&
    new URL(paging.next).hostname.endsWith('zhihu.com');
}

Try / catch

try {
  const results = await zhihuSearch(query, { limit });
} catch (err) {
  if (err.message.includes('malformed next URL')) {
    console.warn('pagination stopped early; returning partial results if available');
  } else throw err;
}

Prevention

When it happens

Trigger: Zhihu returns paging.next as null/undefined, an empty string, a relative or non-Zhihu URL, or a URL that normalizeSearchUrl rejects (e.g. wrong host or scheme) while paging.is_end is false and the result limit is not yet reached.

Common situations: Zhihu API shape change (paging fields renamed), rate-limiting or login walls returning truncated paging info, proxying the API through a gateway that rewrites the next link.

Understand the failure class

Related errors


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