jackwener/OpenCLI · error · CommandExecutionError

WeRead in-book search returned malformed result

Error message

WeRead in-book search returned malformed result

What it means

searchWithinBook calls the WeRead in-book search endpoint via fetchJson and requires data.result to be an array. When the response is missing, null, or has a non-array result field, it throws this CommandExecutionError because pagination cannot proceed on a malformed payload.

Source

Thrown at clis/weread/book-search.js:289

    return searchBookByQuery(target, bookRank);
}

async function searchWithinBook(bookId, query, limit, fragmentSize) {
    const rows = [];
    let maxIdx = 0;
    while (rows.length < limit) {
        const remaining = limit - rows.length;
        const pageSize = remaining < SEARCH_PAGE_SIZE ? remaining : SEARCH_PAGE_SIZE;
        const url = new URL('/web/book/search', WEREAD_WEB_ORIGIN);
        url.searchParams.set('bookId', bookId);
        url.searchParams.set('keyword', query);
        url.searchParams.set('maxIdx', String(maxIdx));
        url.searchParams.set('count', String(pageSize));
        url.searchParams.set('fragmentSize', String(fragmentSize));
        url.searchParams.set('onlyCount', '0');
        const data = await fetchJson(url, 'WeRead in-book search');
        if (!Array.isArray(data?.result)) {
            throw new CommandExecutionError('WeRead in-book search returned malformed result');
        }
        const result = data.result.map((item) => {
            if (!item || typeof item !== 'object') {
                throw new CommandExecutionError('WeRead in-book search returned malformed match');
            }
            const snippet = normalizeSearchText(item.abstract);
            const searchIdx = parseOptionalFiniteNumber(item.searchIdx);
            if (!snippet || searchIdx == null || searchIdx <= 0) {
                throw new CommandExecutionError('WeRead in-book search returned malformed match');
            }
            return {
                ...item,
                abstract: snippet,
                chapterIdx: parseOptionalFiniteNumber(item.chapterIdx),
                chapterUid: parseOptionalFiniteNumber(item.chapterUid),
                searchIdx,
            };
        });

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Log the raw response body to see the actual envelope and adjust expectations.
  2. Re-authenticate / refresh cookies if the endpoint returned an error envelope.
  3. Check for a WeRead API schema update and update the parser.
  4. Retry later if the endpoint is throttling.
Defensive patterns

Strategy: retry

Type guard

function hasResultArray(data) {
  return data != null && typeof data === 'object' && Array.isArray(data.result);
}

Try / catch

try {
  return await searchWithinBook(bookId, query);
} catch (e) {
  if (e instanceof CommandExecutionError && e.message.includes('malformed result')) {
    await sleep(1500);
    return searchWithinBook(bookId, query); // transient error envelope
  }
  throw e;
}

Prevention

When it happens

Trigger: The in-book search API responds with JSON whose shape differs from expected — e.g. {code: -1} error envelope, an object instead of array, or result omitted — after a successful HTTP 200.

Common situations: WeRead API version change; rate limiting or auth expiry returning an error envelope with HTTP 200; searching in a book whose index isn't searchable.

Understand the failure class

Related errors


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