{"record":{"id":"78d59728fe8cbc51","repo":"jackwener/OpenCLI","slug":"no-purchased-courses-found-login-session-may-hav","errorCode":null,"errorMessage":"No purchased courses found — login session may have expired or the \"内容\" tab has no items","messagePattern":"No purchased courses found — login session may have expired or the \"内容\" tab has no items","errorType":"exception","errorClass":"EmptyResultError","httpStatus":null,"severity":"error","filePath":"clis/xiaoe/courses.js","lineNumber":105,"sourceCode":"  }\n  return results;\n})()`;\n}\n\nasync function getXiaoeCourses(page) {\n    let rows;\n    try {\n        await page.goto('https://study.xiaoe-tech.com/', { waitUntil: 'load', settleMs: 8000 });\n        rows = await page.evaluate(buildCoursesScript());\n    } catch (error) {\n        const message = error instanceof Error ? error.message : String(error);\n        throw new CommandExecutionError(\n            `Failed to list xiaoe courses: ${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/courses',\n            'No purchased courses found — login session may have expired or the \"内容\" tab has no items',\n        );\n    }\n    return rows;\n}\n\nexport const coursesCommand = cli({\n    site: 'xiaoe',\n    name: 'courses',\n    access: 'read',\n    description: '列出已购小鹅通课程（含 URL 和店铺名）',\n    domain: 'study.xiaoe-tech.com',\n    strategy: Strategy.COOKIE,\n    browser: true,\n    columns: ['title', 'shop', 'url'],\n    func: getXiaoeCourses,\n});","sourceCodeStart":87,"sourceCodeEnd":123,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/xiaoe/courses.js#L87-L123","documentation":"The study.xiaoe-tech.com page evaluated fine but returned no course rows. The library treats an empty result as EmptyResultError for xiaoe/courses, since purchased courses should exist for an authenticated user — the most likely cause is an expired login session or the '内容' (Content) tab genuinely having no items.","triggerScenarios":"page.evaluate(buildCoursesScript()) returns [] or a non-array: the '内容' tab is empty, the evaluator ran before the course list rendered, or the user is logged out and the DOM is an auth shell.","commonSituations":"Expired session cookie producing an empty-shell page; a brand-new account with no purchased content; slow lazy-loading of the course list past the settle window; site redesign renaming the '内容' tab.","solutions":["Log back in to xiaoe and retry the command","Confirm in a browser that the account actually has items under the '内容' tab","Retry once — the list may still have been loading","Update the selectors/flow in buildCoursesScript if the site layout changed"],"exampleFix":null,"handlingStrategy":"fallback","validationCode":"null","typeGuard":"null","tryCatchPattern":"try {\n  const courses = await getXiaoeCourses();\n} catch (e) {\n  if (e.name === 'EmptyResultError' && /No purchased courses found/.test(e.message)) {\n    await refreshXiaoeSession();\n    const retry = await getXiaoeCourses();\n    if (!retry.length) throw new Error('account genuinely has no items under 内容');\n    return retry;\n  }\n  throw e;\n}","preventionTips":["Confirm the account actually owns content under the '内容' tab before automating","Re-login before long-running course-list jobs","Retry once in case lazy loading missed the settle window","Watch for site redesigns that rename or move the '内容' tab"],"tags":["empty-result","auth-expired","xiaoe"],"backgroundTag":"session-expired","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}