{"record":{"id":"758c8dd575142b76","repo":"jackwener/OpenCLI","slug":"browser-session-required-for-substack-feed","errorCode":null,"errorMessage":"Browser session required for substack feed","messagePattern":"Browser session required for substack feed","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/substack/utils.js","lineNumber":12,"sourceCode":"import { CommandExecutionError } from '@jackwener/opencli/errors';\nconst FEED_POST_LINK_SELECTOR = 'a[href*=\"/home/post/\"], a[href*=\"/p/\"]';\nconst ARCHIVE_POST_LINK_SELECTOR = 'a[href*=\"/p/\"]';\nexport function buildSubstackBrowseUrl(category) {\n    if (!category || category === 'all')\n        return 'https://substack.com/';\n    const slug = category === 'tech' ? 'technology' : category;\n    return `https://substack.com/browse/${slug}`;\n}\nexport async function loadSubstackFeed(page, url, limit) {\n    if (!page)\n        throw new CommandExecutionError('Browser session required for substack feed');\n    await page.goto(url);\n    await page.wait({ selector: FEED_POST_LINK_SELECTOR, timeout: 5 });\n    const data = await page.evaluate(`\n    (async () => {\n      await new Promise((resolve) => setTimeout(resolve, 3000));\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      const allLinks = Array.from(document.querySelectorAll('a')).filter((link) => {\n        const href = link.getAttribute('href') || '';\n        return href.includes('/home/post/') || href.includes('/p/');\n      });\n\n      for (const linkEl of allLinks) {\n        let postUrl = linkEl.getAttribute('href') || '';\n        if (!postUrl) continue;","sourceCodeStart":1,"sourceCodeEnd":30,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/substack/utils.js#L1-L30","documentation":"loadSubstackFeed requires an active browser session (a page object). If no page is provided, it throws a CommandExecutionError stating a browser session is required, because the feed is rendered client-side and cannot be fetched with plain HTTP.","triggerScenarios":"Calling loadSubstackFeed with page = null/undefined, e.g. running the substack feed command without opening/launching a browser session first, or in a headless script that never creates a page.","commonSituations":"Running CLI subcommands in scripts without the browser-session flag, environments where browser launch was skipped or failed silently, CI runners without a display/browser installed.","solutions":["Launch a browser session before loading the feed (use the CLI's browser-session option)","Ensure a browser binary is installed and launchable in your environment","Guard scripts to create the page before calling loadSubstackFeed","Fall back to the Substack RSS/Atom feed if a plain-HTTP alternative is acceptable"],"exampleFix":"// before\nawait loadSubstackFeed(null, 'https://substack.com/browse/technology', 10); // throws\n// after\nconst page = await openBrowserSession(); // launch first\nawait loadSubstackFeed(page, 'https://substack.com/browse/technology', 10);","handlingStrategy":"validation","validationCode":"function requirePage(page) { if (!page || typeof page.goto !== 'function') throw new Error('open a browser session before loading the substack feed'); }\nrequirePage(page);","typeGuard":"function hasPage(p) { return p != null && typeof p.goto === 'function' && typeof p.evaluate === 'function'; }","tryCatchPattern":"try { await loadSubstackFeed(page, url, limit); } catch (e) { if (/Browser session required/.test(e.message)) { page = await openBrowserSession(); await loadSubstackFeed(page, url, limit); } else throw e; }","preventionTips":["Always create a browser session before feed commands","Assert the page object exists in scripts","Verify browser binaries are installed in CI","Fall back to RSS feeds for non-browser pipelines"],"tags":["browser-session","substack","precondition"],"backgroundTag":"browser-session-required","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}