{"record":{"id":"32e6aa54276da743","repo":"jackwener/OpenCLI","slug":"no-article-content-extracted-login-session-may-h","errorCode":null,"errorMessage":"No article content extracted — login session may have expired or the page renders an empty shell","messagePattern":"No article content extracted — login session may have expired or the page renders an empty shell","errorType":"exception","errorClass":"EmptyResultError","httpStatus":null,"severity":"error","filePath":"clis/xiaoe/content.js","lineNumber":150,"sourceCode":"    try {\n        await page.goto(url, { waitUntil: 'load', settleMs: 6000 });\n        rows = await page.evaluate(buildContentScript());\n    } catch (error) {\n        const message = error instanceof Error ? error.message : String(error);\n        throw new CommandExecutionError(\n            `Failed to extract xiaoe content: ${message}`,\n            'page may not have rendered or auth may be required',\n        );\n    }\n    if (!Array.isArray(rows) || rows.length === 0) {\n        throw new EmptyResultError(\n            'xiaoe/content',\n            'No rows returned from page evaluator (page structure may have changed)',\n        );\n    }\n    const row = rows[0];\n    if (!row || typeof row.content !== 'string' || row.content.length === 0) {\n        throw new EmptyResultError(\n            'xiaoe/content',\n            'No article content extracted — login session may have expired or the page renders an empty shell',\n        );\n    }\n    return rows;\n}\n\nexport const contentCommand = cli({\n    site: 'xiaoe',\n    name: 'content',\n    access: 'read',\n    description: '提取小鹅通图文页面内容为文本',\n    domain: 'h5.xet.citv.cn',\n    strategy: Strategy.COOKIE,\n    browser: true,\n    args: [\n        { name: 'url', required: true, positional: true, help: '页面 URL' },\n    ],","sourceCodeStart":132,"sourceCodeEnd":168,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/xiaoe/content.js#L132-L168","documentation":"The evaluator returned rows but rows[0].content was missing, non-string, or an empty string. Since content is the column this adapter exists to produce, an empty extraction is surfaced as EmptyResultError instead of silently returning [{content: ''}]. Xiaoe routinely renders an empty shell when the login cookie has expired, so the hint points at auth first.","triggerScenarios":"Rows extracted but no element matched with more than CONTENT_MIN_LENGTH (50) characters of text — e.g. logged-out shell page, empty fallback containers (main/#app/body) yielding short boilerplate text.","commonSituations":"Expired xiaoe login session (most common); the article/course really is empty or paywalled; CSS changed so text now lives in a container the selector chain misses with only a stub of text.","solutions":["Log back in to xiaoe / refresh the session cookies and retry","Open the URL in a browser to confirm the article actually has content","Check whether the content moved to a container outside CONTENT_SELECTORS and update the selectors","Lower expectations: if the content is paywalled, a paid account is required"],"exampleFix":null,"handlingStrategy":"fallback","validationCode":"null","typeGuard":"null","tryCatchPattern":"try {\n  const rows = await getXiaoeContent(url);\n} catch (e) {\n  if (e.name === 'EmptyResultError' && /login session may have expired/.test(e.message)) {\n    await refreshXiaoeSession();\n    return getXiaoeContent(url);\n  }\n  throw e;\n}","preventionTips":["Refresh the xiaoe cookie session before scheduled extraction runs","Confirm the article is publicly viewable and not paywalled","Open the URL in a real browser to check it is not an empty shell","If persistent after re-login, inspect whether the text container still matches CONTENT_SELECTORS"],"tags":["empty-result","auth-expired","cookie","xiaoe"],"backgroundTag":"session-expired","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}