{"record":{"id":"2d6696ce5bf0dd98","repo":"jackwener/OpenCLI","slug":"browser-session-required-for-medium-posts","errorCode":null,"errorMessage":"Browser session required for medium posts","messagePattern":"Browser session required for medium posts","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/medium/utils.js","lineNumber":13,"sourceCode":"import { CommandExecutionError } from '@jackwener/opencli/errors';\nexport function buildMediumTagUrl(topic) {\n    return topic ? `https://medium.com/tag/${encodeURIComponent(topic)}` : 'https://medium.com/tag/technology';\n}\nexport function buildMediumSearchUrl(keyword) {\n    return `https://medium.com/search?q=${encodeURIComponent(keyword)}`;\n}\nexport function buildMediumUserUrl(username) {\n    return username.startsWith('@') ? `https://medium.com/${username}` : `https://medium.com/@${username}`;\n}\nexport async function loadMediumPosts(page, url, limit) {\n    if (!page)\n        throw new CommandExecutionError('Browser session required for medium posts');\n    await page.goto(url);\n    await page.wait({ selector: 'article', timeout: 5 });\n    const data = await page.evaluate(`\n    (async () => {\n      await new Promise((resolve) => setTimeout(resolve, 3000));\n\n      const limit = ${Math.max(1, Math.min(limit, 50))};\n      const normalize = (value) => (value || '').replace(/\\\\s+/g, ' ').trim();\n      const posts = [];\n      const seen = new Set();\n\n      for (const article of Array.from(document.querySelectorAll('article'))) {\n        try {\n          const titleEl = article.querySelector('h2, h3, h1');\n          const title = normalize(titleEl?.textContent);\n          if (!title) continue;\n\n          const linkEl = titleEl?.closest('a') || article.querySelector('a[href*=\"/@\"], a[href*=\"/p/\"]');","sourceCodeStart":1,"sourceCodeEnd":31,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/medium/utils.js#L1-L31","documentation":"loadMediumPosts scrapes Medium user pages through a browser (page.goto/wait/evaluate). It requires an active browser session; when page is null/undefined it throws CommandExecutionError 'Browser session required for medium posts' instead of attempting a headless HTTP fetch.","triggerScenarios":"Calling loadMediumPosts(page=null, url, limit) or invoking the wrapping medium posts command without a browser session/bridge established (e.g. browser not started, Browser Bridge not connected, session closed before the call).","commonSituations":"Running the command in an environment without a logged-in/available browser; forgetting to initialize the browser adapter before calling the medium posts helper; a previously-open page that crashed or was closed leaving `page` falsy.","solutions":["Start the browser session/Browser Bridge before running the medium posts command (per the CLI's browser setup instructions).","Verify the page object is passed to loadMediumPosts — never call it with an undefined page in custom scripts.","Re-open the browser if a previous session crashed, then rerun the command.","If you need data without a browser, use the RSS-based medium tag command instead, which does not require a page."],"exampleFix":"// before\nawait loadMediumPosts(null, 'https://medium.com/@user', 5); // throws\n// after\nconst page = await browser.newPage();\nawait loadMediumPosts(page, 'https://medium.com/@user', 5);","handlingStrategy":"type-guard","validationCode":"if (!page) {\n  throw new Error('Start the browser session/Browser Bridge before loading medium posts');\n}","typeGuard":"function hasBrowserPage(p) {\n  return p != null && typeof p.goto === 'function' && typeof p.evaluate === 'function';\n}","tryCatchPattern":"try {\n  await loadMediumPosts(page, url, limit);\n} catch (e) {\n  if (/Browser session required/.test(e.message)) {\n    const page = await startBrowserBridge();\n    await loadMediumPosts(page, url, limit);\n  } else throw e;\n}","preventionTips":["Always initialize the browser/Browser Bridge before browser-based commands.","Assert page existence in wrapper scripts before calling loadMediumPosts.","Recreate the page after crashes instead of reusing a dead reference.","Prefer the RSS-based medium tag command when a browser is unavailable."],"tags":["browser","cli","command-execution-error","precondition"],"backgroundTag":"browser-session-required","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}