jackwener/OpenCLI · error · CommandExecutionError

Browser session required for substack feed

Error message

Browser session required for substack feed

What it means

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.

Source

Thrown at clis/substack/utils.js:12

import { CommandExecutionError } from '@jackwener/opencli/errors';
const FEED_POST_LINK_SELECTOR = 'a[href*="/home/post/"], a[href*="/p/"]';
const ARCHIVE_POST_LINK_SELECTOR = 'a[href*="/p/"]';
export function buildSubstackBrowseUrl(category) {
    if (!category || category === 'all')
        return 'https://substack.com/';
    const slug = category === 'tech' ? 'technology' : category;
    return `https://substack.com/browse/${slug}`;
}
export async function loadSubstackFeed(page, url, limit) {
    if (!page)
        throw new CommandExecutionError('Browser session required for substack feed');
    await page.goto(url);
    await page.wait({ selector: FEED_POST_LINK_SELECTOR, timeout: 5 });
    const data = await page.evaluate(`
    (async () => {
      await new Promise((resolve) => setTimeout(resolve, 3000));
      const limit = ${Math.max(1, Math.min(limit, 50))};
      const normalize = (value) => (value || '').replace(/\\s+/g, ' ').trim();
      const posts = [];
      const seen = new Set();

      const allLinks = Array.from(document.querySelectorAll('a')).filter((link) => {
        const href = link.getAttribute('href') || '';
        return href.includes('/home/post/') || href.includes('/p/');
      });

      for (const linkEl of allLinks) {
        let postUrl = linkEl.getAttribute('href') || '';
        if (!postUrl) continue;

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Launch a browser session before loading the feed (use the CLI's browser-session option)
  2. Ensure a browser binary is installed and launchable in your environment
  3. Guard scripts to create the page before calling loadSubstackFeed
  4. Fall back to the Substack RSS/Atom feed if a plain-HTTP alternative is acceptable

Example fix

// before
await loadSubstackFeed(null, 'https://substack.com/browse/technology', 10); // throws
// after
const page = await openBrowserSession(); // launch first
await loadSubstackFeed(page, 'https://substack.com/browse/technology', 10);
Defensive patterns

Strategy: validation

Validate before calling

function requirePage(page) { if (!page || typeof page.goto !== 'function') throw new Error('open a browser session before loading the substack feed'); }
requirePage(page);

Type guard

function hasPage(p) { return p != null && typeof p.goto === 'function' && typeof p.evaluate === 'function'; }

Try / catch

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; }

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29). Data as JSON: /api/errors/758c8dd575142b76. Report an issue: GitHub.