jackwener/OpenCLI · error · CommandExecutionError

Zhihu search returned malformed result row identity

Error message

Zhihu search returned malformed result row identity

What it means

normalizeResultItem validates that each search result row has an identity triple: a recognized type (answer/article/question), a non-empty key, URL, and title. If any of these is missing after normalization (itemKey/itemUrl return empty or title strips to empty), the CLI throws this CommandExecutionError because a row without identity cannot be displayed or linked reliably. It is a defensive guard against Zhihu's search API returning incomplete or unexpected objects.

Source

Thrown at clis/zhihu/search.js:110

    }
    if (!payload.paging || typeof payload.paging !== 'object') {
        throw new CommandExecutionError('Zhihu search returned malformed paging data', `URL: ${url}`);
    }
    return payload;
}

function normalizeResultItem(item) {
    if (!item || typeof item !== 'object' || item.type !== 'search_result' || !item.object || typeof item.object !== 'object') {
        return null;
    }
    const obj = item.object;
    if (obj.type !== 'answer' && obj.type !== 'article' && obj.type !== 'question') return null;
    const key = itemKey(item);
    const url = itemUrl(obj);
    const question = obj.question || {};
    const title = stripHtml(obj.title || question.name || question.title || '');
    if (!key || !url || !title) {
        throw new CommandExecutionError('Zhihu search returned malformed result row identity');
    }
    return {
        item,
        key,
        row: {
            title,
            type: obj.type,
            author: obj.author?.name || '',
            votes: obj.voteup_count || 0,
            url,
        },
    };
}

cli({
    site: 'zhihu',
    name: 'search',
    access: 'read',

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Update/re-run the search; malformed rows are often transient upstream data issues
  2. Check the raw API response (log data.data items) to see which field is missing
  3. Update the itemKey/itemUrl/stripHtml helpers to match the current Zhihu API field names
  4. Skip malformed rows (return null) instead of throwing if you control the fork

Example fix

// before
if (!key || !url || !title) {
    throw new CommandExecutionError('Zhihu search returned malformed result row identity');
}
// after
if (!key || !url || !title) {
    console.warn('skipping malformed row', item);
    return null;
}
Defensive patterns

Strategy: validation

Validate before calling

function isUsableRow(item) {
  const t = item?.target;
  return t && ['answer','article','question'].includes(t.type) &&
    !!t.id && !!(t.title || t.question?.title || t.question?.name);
}
const usable = (data.data || []).filter(isUsableRow);

Type guard

function hasRowIdentity(obj) {
  return typeof obj === 'object' && obj !== null &&
    typeof obj.type === 'string' &&
    ['answer','article','question'].includes(obj.type) &&
    typeof obj.title === 'string' && obj.title.trim() !== '' &&
    typeof obj.url === 'string' && obj.url !== '';
}

Try / catch

try {
  const results = await zhihuSearch(query, opts);
} catch (err) {
  if (err.message.includes('malformed result row identity')) {
    console.error('Zhihu API returned an unidentifiable row; retry or inspect raw payload', err);
  } else throw err;
}

Prevention

When it happens

Trigger: A search result object from Zhihu's API has type answer/article/question but itemKey(item) returns empty, itemUrl(obj) yields no URL, or stripHtml of obj.title/question.name/question.title produces an empty string.

Common situations: Zhihu changes its search API shape (renamed fields), soft-deleted or moderated items appear with empty titles, or scraping/HTML-stripping removes all content from a title, or a new result type passes the type check but lacks the key the itemKey function expects.

Understand the failure class

Related errors


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