puppeteer/puppeteer · error

Could not parse JSON from ${url}

Error message

Could not parse JSON from ${url}

What it means

Thrown by getJSON when the body fetched from url could not be JSON.parse'd. The original SyntaxError is swallowed and replaced with a clearer message naming the URL. Because getText already handles HTTP-level errors (>=400), reaching JSON.parse means the request returned 2xx with a non-JSON body — typically an HTML error/landing page from a proxy or a misrouted URL.

Source

Thrown at packages/browsers/src/httpUtil.ts:171

          }
        });
        response.pipe(file);
      });
      request.on('error', error => {
        return reject(error);
      });
    } catch (error) {
      reject(error);
    }
  });
}

export async function getJSON(url: URL): Promise<unknown> {
  const text = await getText(url);
  try {
    return JSON.parse(text);
  } catch {
    throw new Error('Could not parse JSON from ' + url.toString());
  }
}

export function getText(url: URL): Promise<string> {
  return new Promise(async (resolve, reject) => {
    try {
      const request = await httpRequest(
        url,
        'GET',
        response => {
          let data = '';
          if (response.statusCode && response.statusCode >= 400) {
            return reject(new Error(`Got status code ${response.statusCode}`));
          }
          response.on('data', chunk => {
            data += chunk;
          });
          response.on('end', () => {

View on GitHub (pinned to d484e21c17)

Solutions

  1. Manually curl the URL and inspect Content-Type and the first bytes of the body.
  2. Correct baseUrl to the official endpoint or a mirror known to serve JSON.
  3. Bypass/whitelist the endpoint in your proxy to prevent HTML injection.
  4. Catch the error and fall back to a known-good pinned URL.
Defensive patterns

Strategy: try-catch

Validate before calling

async function bodyIsJson(url: URL): Promise<boolean> {
  const res = await fetch(url);
  const ct = res.headers.get('content-type') ?? '';
  return ct.includes('application/json') && res.ok;
}
if (!await bodyIsJson(url)) throw new Error(`Endpoint ${url} does not serve JSON`);

Try / catch

try {
  return await getJSON(url);
} catch (e) {
  if ((e as Error).message.startsWith('Could not parse JSON')) {
    throw new Error(`${url} returned non-JSON (likely an HTML proxy/login page). Check baseUrl.`);
  }
  throw e;
}

Prevention

When it happens

Trigger: A custom baseUrl returns HTML (login page, 200-status error page) instead of JSON; a corporate proxy intercepts with a captive portal; product-details / JSON endpoints moved and now 302 to an HTML page; trailing slash differences yielding a directory listing.

Common situations: Misconfigured baseUrl for Firefox product-details; storage bucket returning XML error JSON; localized ISP injection; the JSON endpoint changed path upstream.

Related errors


AI-assisted analysis of puppeteer/puppeteer@d484e21c17 (2026-08-12). Data as JSON: /api/errors/a595f5ddceafbdb2. Report an issue: GitHub.