{"record":{"id":"8f4b846632dba52a","repo":"jackwener/OpenCLI","slug":"weread-in-book-search-returned-malformed-result","errorCode":null,"errorMessage":"WeRead in-book search returned malformed result","messagePattern":"WeRead in-book search returned malformed result","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/weread/book-search.js","lineNumber":289,"sourceCode":"    return searchBookByQuery(target, bookRank);\n}\n\nasync function searchWithinBook(bookId, query, limit, fragmentSize) {\n    const rows = [];\n    let maxIdx = 0;\n    while (rows.length < limit) {\n        const remaining = limit - rows.length;\n        const pageSize = remaining < SEARCH_PAGE_SIZE ? remaining : SEARCH_PAGE_SIZE;\n        const url = new URL('/web/book/search', WEREAD_WEB_ORIGIN);\n        url.searchParams.set('bookId', bookId);\n        url.searchParams.set('keyword', query);\n        url.searchParams.set('maxIdx', String(maxIdx));\n        url.searchParams.set('count', String(pageSize));\n        url.searchParams.set('fragmentSize', String(fragmentSize));\n        url.searchParams.set('onlyCount', '0');\n        const data = await fetchJson(url, 'WeRead in-book search');\n        if (!Array.isArray(data?.result)) {\n            throw new CommandExecutionError('WeRead in-book search returned malformed result');\n        }\n        const result = data.result.map((item) => {\n            if (!item || typeof item !== 'object') {\n                throw new CommandExecutionError('WeRead in-book search returned malformed match');\n            }\n            const snippet = normalizeSearchText(item.abstract);\n            const searchIdx = parseOptionalFiniteNumber(item.searchIdx);\n            if (!snippet || searchIdx == null || searchIdx <= 0) {\n                throw new CommandExecutionError('WeRead in-book search returned malformed match');\n            }\n            return {\n                ...item,\n                abstract: snippet,\n                chapterIdx: parseOptionalFiniteNumber(item.chapterIdx),\n                chapterUid: parseOptionalFiniteNumber(item.chapterUid),\n                searchIdx,\n            };\n        });","sourceCodeStart":271,"sourceCodeEnd":307,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/weread/book-search.js#L271-L307","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Log the raw response body to see the actual envelope and adjust expectations.","Re-authenticate / refresh cookies if the endpoint returned an error envelope.","Check for a WeRead API schema update and update the parser.","Retry later if the endpoint is throttling."],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":"function hasResultArray(data) {\n  return data != null && typeof data === 'object' && Array.isArray(data.result);\n}","tryCatchPattern":"try {\n  return await searchWithinBook(bookId, query);\n} catch (e) {\n  if (e instanceof CommandExecutionError && e.message.includes('malformed result')) {\n    await sleep(1500);\n    return searchWithinBook(bookId, query); // transient error envelope\n  }\n  throw e;\n}","preventionTips":["Refresh auth/cookies when the API starts returning error envelopes.","Rate-limit calls to avoid degraded responses.","Log raw responses in a debug mode to catch schema changes early."],"tags":["api-schema","search","weread"],"backgroundTag":"api-response-schema-mismatch","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}