jackwener/OpenCLI · error · CliError

FETCH_ERROR

FETCH_ERROR

Error message

Browser fetch failed for ${targetUrl}: ${result.error}

What it means

fetchJson (src/browser/base-page.ts:261) performs fetch inside the page context (via page.evaluate) so the request uses the browser's cookies and profile. When the in-page fetch reports an error (network failure, blocked request, aborted), the result carries result.error and the method throws CliError with code FETCH_ERROR, plus a hint to check reachability and profile access.

Source

Thrown at src/browser/base-page.ts:261

            error: error instanceof Error ? error.message : String(error),
          };
        } finally {
          clearTimeout(timer);
        }
      })()
    `, { request }) as {
      ok?: boolean;
      status?: number;
      statusText?: string;
      url?: string;
      contentType?: string;
      text?: string;
      error?: string;
    };

    const targetUrl = result.url || url;
    if (result.error) {
      throw new CliError(
        'FETCH_ERROR',
        `Browser fetch failed for ${targetUrl}: ${result.error}`,
        'Check that the page is reachable and the current browser profile has access.',
      );
    }
    if (!result.ok) {
      throw new CliError(
        'FETCH_ERROR',
        `HTTP ${result.status ?? 0}${result.statusText ? ` ${result.statusText}` : ''} from ${targetUrl}`,
        previewText(result.text),
      );
    }

    const text = result.text ?? '';
    if (!text.trim()) return null;
    try {
      return JSON.parse(text);
    } catch {

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Open the target URL directly in the browser tab to confirm reachability and fix DNS/proxy/VPN issues.
  2. If mixed content is the cause, use the HTTPS form of the URL.
  3. Temporarily disable ad blockers/content blockers or whitelist the domain, since ERR_BLOCKED_BY_CLIENT surfaces as a fetch error.
  4. Catch the CliError, inspect result.error in the message, and fall back to a server-side (Node) fetch if browser-context fetch isn't required.
  5. Check the page's service workers and extension content scripts that may intercept or cancel fetches.

Example fix

// before
const data = await page.fetchJson('http://api.internal.local/endpoint');
// after
const data = await page.fetchJson('https://api.internal.local/endpoint'); // or try/catch FETCH_ERROR and fall back to server-side fetch
Defensive patterns

Strategy: try-catch

Validate before calling

// reachability pre-check before the browser-context fetch:
const reachable = await page.evaluate(`(async () => { try { const r = await fetch(${JSON.stringify(url)}, { method: 'HEAD' }); return r.ok || r.status > 0; } catch { return false; } })()`);
if (!reachable) console.warn('URL unreachable from page context:', url);

Type guard

function isCliError(err: unknown, code?: string): err is CliError {
  return err instanceof CliError || (typeof err === 'object' && err !== null && (err as any).code === (code ?? 'FETCH_ERROR'));
}

Try / catch

try {
  return await page.fetchJson(url);
} catch (err) {
  if (isCliError(err, 'FETCH_ERROR')) {
    console.warn(`browser fetch failed: ${err.message}; hint: ${err.hint}`);
    return serverFetchJson(url); // fall back to Node-side fetch
  }
  throw err;
}

Prevention

When it happens

Trigger: The in-page fetch rejects or returns {error: ...}: DNS failure, ERR_BLOCKED_BY_CLIENT (ad blocker), mixed-content blocking (HTTPS page fetching HTTP URL), CORS handled as a network error, request timeout/abort, or the page navigating away mid-fetch.

Common situations: Extensions/ad-blockers cancelling the request; fetching http:// endpoints from https:// pages; corporate proxy/VPN blocking the host; fetching an internal hostname from a page loaded on the public internet; service worker intercepting and failing the request.

Related errors


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