{"record":{"id":"3ab75d083a427272","repo":"jackwener/OpenCLI","slug":"unexpected-response-structure-3ab75d","errorCode":null,"errorMessage":"Unexpected response structure","messagePattern":"Unexpected response structure","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"clis/xiaohongshu/creator-stats.js","lineNumber":52,"sourceCode":"        await page.goto('https://creator.xiaohongshu.com/new/home');\n        const data = await page.evaluate(`\n      async () => {\n        try {\n          const resp = await fetch('/api/galaxy/creator/data/note_detail_new', {\n            credentials: 'include',\n          });\n          if (!resp.ok) return { error: 'HTTP ' + resp.status };\n          return await resp.json();\n        } catch (e) {\n          return { error: e.message };\n        }\n      }\n    `);\n        if (data?.error) {\n            throw new Error(data.error + '. Are you logged into creator.xiaohongshu.com?');\n        }\n        if (!data?.data) {\n            throw new Error('Unexpected response structure');\n        }\n        const stats = data.data[period];\n        if (!stats) {\n            throw new EmptyResultError('xiaohongshu creator-stats', `No data for period \"${period}\". Available: ${Object.keys(data.data).join(', ')}`);\n        }\n        // Format daily trend as sparkline-like summary\n        const formatTrend = (list) => {\n            if (!list || !list.length)\n                return '-';\n            return list.map((d) => d.count).join(' → ');\n        };\n        return [\n            { metric: '观看数 (views)', total: stats.view_count ?? 0, trend: formatTrend(stats.view_list) },\n            { metric: '平均观看时长 (avg view time ms)', total: stats.view_time_avg ?? 0, trend: formatTrend(stats.view_time_list) },\n            { metric: '主页访问 (home views)', total: stats.home_view_count ?? 0, trend: formatTrend(stats.home_view_list) },\n            { metric: '点赞数 (likes)', total: stats.like_count ?? 0, trend: formatTrend(stats.like_list) },\n            { metric: '收藏数 (collects)', total: stats.collect_count ?? 0, trend: formatTrend(stats.collect_list) },\n            { metric: '评论数 (comments)', total: stats.comment_count ?? 0, trend: formatTrend(stats.comment_list) },","sourceCodeStart":34,"sourceCodeEnd":70,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/xiaohongshu/creator-stats.js#L34-L70","documentation":"Same structural guard as creator-profile: thrown when the creator-stats evaluate result lacks a `data` property, so the CLI refuses to index into `data.data[period]`. It indicates the page returned something other than the expected `{ data: {...} }` envelope.","triggerScenarios":"The in-page script resolved to null/undefined or an object without `data` — e.g. the stats endpoint returned an HTML error page, an anti-bot interstitial, or the API schema changed.","commonSituations":"Logged-out or partially authenticated session on creator.xiaohongshu.com; Xiaohongshu backend changed the stats payload shape; transient CDN/captcha responses replacing the JSON body.","solutions":["Confirm you are logged into creator.xiaohongshu.com in the automation browser and the dashboard renders","Inspect the raw evaluate result before the throw to see the actual payload","Retry — a transient interstitial can produce an empty payload","Update the in-page parsing script if Xiaohongshu changed its response schema"],"exampleFix":"// before\nif (!data?.data) {\n    throw new Error('Unexpected response structure');\n}\n// after\nif (!data?.data) {\n    throw new Error('Unexpected response structure: ' + JSON.stringify(data).slice(0, 200));\n}","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"function hasStatsEnvelope(v) { return v !== null && typeof v === 'object' && v.data !== null && typeof v.data === 'object'; }","tryCatchPattern":"try {\n  const stats = await getCreatorStats({ period });\n} catch (e) {\n  if (e.message === 'Unexpected response structure') {\n    // inspect raw payload / re-auth / retry after transient interstitial\n  } else { throw e; }\n}","preventionTips":["Verify the dashboard loads manually in the same browser profile before automating","Capture the raw response on failure to catch API shape changes","Retry once on transient failures (captchas, slow renders)"],"tags":["puppeteer","response-parsing","scraping","api-change"],"backgroundTag":"unexpected-response-shape","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}