{"record":{"id":"a269107e3005f3b2","repo":"jackwener/OpenCLI","slug":"unexpected-xiaohongshu-search-harvest-row-index","errorCode":null,"errorMessage":"Unexpected Xiaohongshu search harvest row ${index + 1} shape; expected an object.","messagePattern":"Unexpected Xiaohongshu search harvest row (.+?) shape; expected an object\\.","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/xiaohongshu/search.js","lineNumber":293,"sourceCode":"    return results;\n}\n\nfunction isTrustedAuthorUrl(url, webHost) {\n    if (url === '')\n        return true;\n    try {\n        const parsed = new URL(url);\n        return parsed.protocol === 'https:' &&\n            parsed.hostname.toLowerCase() === webHost.toLowerCase() &&\n            /^\\/user\\/profile\\/[^/]+\\/?$/i.test(parsed.pathname);\n    }\n    catch {\n        return false;\n    }\n}\nfunction requireTrustedHarvestRow(row, index, webHost) {\n    if (!row || typeof row !== 'object' || Array.isArray(row)) {\n        throw new CommandExecutionError(`Unexpected Xiaohongshu search harvest row ${index + 1} shape; expected an object.`);\n    }\n    for (const field of ['title', 'author', 'likes', 'url', 'author_url']) {\n        if (typeof row[field] !== 'string') {\n            throw new CommandExecutionError(`Unexpected Xiaohongshu search harvest row ${index + 1} shape; expected string ${field}.`);\n        }\n    }\n    if (!noteUrlInfo(row.url, webHost).key) {\n        throw new CommandExecutionError(`Unexpected Xiaohongshu search harvest row ${index + 1} URL; expected a trusted note URL.`);\n    }\n    if (!isTrustedAuthorUrl(row.author_url, webHost)) {\n        throw new CommandExecutionError(`Unexpected Xiaohongshu search harvest row ${index + 1} author URL; expected a trusted profile URL.`);\n    }\n    return row;\n}\nfunction requireHarvestPayload(payload, webHost) {\n    const result = unwrapEvaluateResult(payload);\n    const diag = result?.diag;\n    if (!result || typeof result !== 'object' || Array.isArray(result) || !Array.isArray(result.rows) ||","sourceCodeStart":275,"sourceCodeEnd":311,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/xiaohongshu/search.js#L275-L311","documentation":"requireTrustedHarvestRow validates each row harvested from the xiaohongshu search page. A row must be a non-null, non-array object; anything else (null, a string, an array, a number) is rejected because the downstream pipeline assumes object-shaped rows with known fields.","triggerScenarios":"The in-page harvest script returned malformed data for row index+1 — e.g. a page scrape produced strings instead of objects, or the extraction script's shape contract drifted from what the page rendered.","commonSituations":"Xiaohongshu changed search-result markup so the harvest script collects wrong nodes, an anti-bot interstitial replaced results with junk, or a bug in the injected harvest script maps rows to arrays/strings.","solutions":["Re-run the search — transient anti-bot pages can corrupt one harvest.","Check the CLI version against recent xiaohongshu search DOM changes and update.","Reduce result count or add delays to avoid truncated/partial harvests.","Report the row shape from verbose logs if it persists — the harvest script needs a fix."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":"function isHarvestRow(row) {\n  return row !== null && typeof row === 'object' && !Array.isArray(row);\n}","tryCatchPattern":"try {\n  const rows = await searchNotes(query);\n} catch (e) {\n  if (String(e.message).includes('harvest row') && String(e.message).includes('expected an object')) {\n    // retry once; anti-bot pages can corrupt a single harvest\n    return searchNotes(query);\n  }\n  throw e;\n}","preventionTips":["Retry searches that fail on a single row — transient anti-bot pages are a common cause.","Keep the CLI updated when xiaohongshu changes search-result markup.","Avoid scraping at high frequency, which invites anti-bot interstitials.","Report persistent shape errors with verbose logs."],"tags":["validation","schema","scraping","xiaohongshu"],"backgroundTag":"schema-validation-failed","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}