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
- Install the dependency: `npm install puppeteer` (or `bun add puppeteer`) in the project the detector runs from.
- Reuse an already-launched browser by passing options.browser so the import path is skipped entirely.
- 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
- Add puppeteer to the project's dependencies where URL scanning is supported.
- In CI, install puppeteer and rely on the built-in --no-sandbox handling (process.env.CI).
- When scanning many URLs, pass a single shared options.browser to skip repeated imports/launches.
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
- puppeteer is required for URL scanning. Install: npm install
- Created ${zipFileName} but it is 0 bytes.
- Browser script not found at ${browserScriptPath}
- ${body.error || res.statusText}\n${body.reason}\n${body.hint
- Status failed: ${res.status} ${res.statusText}
AI-assisted analysis of pbakaus/impeccable@d14711ae3d (2026-08-13).
Data as JSON: /api/errors/38d3dc47e072ec04.
Report an issue: GitHub.