pbakaus/impeccable · error

puppeteer is required for URL scanning. Install: npm install

Error message

puppeteer is required for URL scanning. Install: npm install puppeteer

What it means

The URL scanning engine dynamically imports puppeteer (`import('puppeteer')`) to launch a headless browser and run the in-page anti-pattern checks. The import is skipped only when the caller supplies `options.browser` (an already-launched browser instance); otherwise a failure to resolve the puppeteer module is rethrown as this actionable error. It is a dependency/environment error, not a logic error.

Source

Thrown at plugin/skills/impeccable/scripts/detector/engines/browser/detect-url.mjs:181

// ---------------------------------------------------------------------------

async function detectUrl(url, options = {}) {
  const profile = options?.profile;
  const waitUntil = options?.waitUntil || 'networkidle0';
  const settleMs = Number.isFinite(options?.settleMs) ? options.settleMs : 0;
  const viewport = options?.viewport || { width: 1280, height: 800 };
  const externalBrowser = options?.browser || null;
  let puppeteer;
  if (!externalBrowser) {
    try {
      puppeteer = await profileStepAsync(profile, {
        engine: 'browser',
        phase: 'setup',
        ruleId: 'import-puppeteer',
        target: url,
      }, () => import('puppeteer'));
    } catch {
      throw new Error('puppeteer is required for URL scanning. Install: npm install puppeteer');
    }
  }

  // Read the browser detection script — reuse it instead of reimplementing
  const browserScriptPath = path.resolve(
    path.dirname(fileURLToPath(import.meta.url)),
    '..',
    '..',
    'detect-antipatterns-browser.js'
  );
  let browserScript;
  try {
    browserScript = profileStep(profile, {
      engine: 'browser',
      phase: 'setup',
      ruleId: 'read-browser-script',
      target: url,
    }, () => fs.readFileSync(browserScriptPath, 'utf-8'));

View on GitHub (pinned to d14711ae3d)

Solutions

  1. Install the dependency: `npm install puppeteer` (or `bun add puppeteer`) in the project the detector runs from.
  2. Reuse an already-launched browser by passing options.browser so the import path is skipped entirely.
  3. In CI, also ensure Chrome can launch (the code already adds --no-sandbox when process.env.CI is set).

Example fix

// before
await detectUrl('https://example.com'); // no puppeteer, no shared browser

// after (option A — install)
// npm install puppeteer

// after (option B — share a browser)
await detectUrl('https://example.com', { browser: sharedBrowser });
Defensive patterns

Strategy: validation

Validate before calling

async function canResolvePuppeteer() {
  try { await import('puppeteer'); return true; }
  catch { return false; }
}

if (!options.browser && !await canResolvePuppeteer()) {
  throw new Error('puppeteer is not installed; run `npm install puppeteer`');
}
await detectUrl(url, options);

Try / catch

try {
  await detectUrl(url, options);
} catch (e) {
  if (String(e.message).includes('puppeteer is required')) {
    // surface the install hint or fall back to the static (non-browser) detector
    console.error(e.message);
  } else throw e;
}

Prevention

When it happens

Trigger: Calling detectUrl(url) (or the higher-level audit path that reaches it) with no options.browser and with puppeteer not installed in the running project's node_modules. The dynamic import() rejects, the catch block converts it into the user-facing message.

Common situations: Fresh checkout where `npm install puppeteer` was never run; CI image that omits the optional browser dependency; a monorepo where puppeteer is hoisted to a parent node_modules and the detector runs from a workspace that cannot resolve it; running `/impeccable audit` against a live URL before installing browser deps.

Related errors


AI-assisted analysis of pbakaus/impeccable@d14711ae3d (2026-08-13). Data as JSON: /api/errors/38d3dc47e072ec04. Report an issue: GitHub.