{"record":{"id":"e1421633049df01b","repo":"jackwener/OpenCLI","slug":"failed-to-list-xiaoe-courses-message","errorCode":null,"errorMessage":"Failed to list xiaoe courses: ${message}","messagePattern":"Failed to list xiaoe courses: (.+?)","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/xiaoe/courses.js","lineNumber":99,"sourceCode":"    var entry = matchEntry(title, cards[c].__vue__, 0);\n    results.push({\n      title: title,\n      shop: entry ? (entry.shop_name || entry.app_name || '') : '',\n      url: entry ? buildCourseUrl(entry) : '',\n    });\n  }\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 和店铺名）',","sourceCodeStart":81,"sourceCodeEnd":117,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/xiaoe/courses.js#L81-L117","documentation":"getXiaoeCourses loads https://study.xiaoe-tech.com/ in a browser and evaluates buildCoursesScript() to list purchased courses. Any throw from goto or evaluate is wrapped in this CommandExecutionError with the message 'Failed to list xiaoe courses: <inner>' and a hint that the page may not have rendered or auth may be required.","triggerScenarios":"Navigation to study.xiaoe-tech.com fails (network/DNS/TLS/timeout) or the courses page script throws during evaluate (login redirect page, unexpected DOM, runtime error).","commonSituations":"Login session expired so the site redirects to an auth page; study.xiaoe-tech.com is slow to load and 8000ms settle is insufficient; corporate proxy blocks the domain; front-end update breaks the script.","solutions":["Re-authenticate the xiaoe account and retry","Check network/proxy access to study.xiaoe-tech.com","Retry — transient load flakiness with the 8s settle window is possible","Read the inner message (after the colon) for the exact root cause"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// check reachability of the courses portal first\nconst res = await fetch('https://study.xiaoe-tech.com/', { method: 'HEAD' }).catch(() => null);\nif (!res) throw new Error('study.xiaoe-tech.com unreachable');","typeGuard":"null","tryCatchPattern":"try {\n  const courses = await getXiaoeCourses();\n} catch (e) {\n  if (e.name === 'CommandExecutionError' && e.message.startsWith('Failed to list xiaoe courses')) {\n    console.error('Courses load failed:', e.message, '— hint:', e.hint);\n    // re-auth, check network, retry\n  } else throw e;\n}","preventionTips":["Keep the study.xiaoe-tech.com login session fresh","Verify proxy/firewall allows study.xiaoe-tech.com before automation","Retry once on first failure — the 8s settle window may be tight","Read the inner message after 'Failed to list xiaoe courses:' for the root cause"],"tags":["browser-automation","page-navigation","xiaoe"],"backgroundTag":"page-extraction-failed","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}