n8n-io/n8n · error · BrowserExecutableNotFoundError

No executable path for ${browser}

Error message

No executable path for ${browser}

What it means

Thrown as BrowserExecutableNotFoundError by AgentBrowserAdapter.launch when the resolved config has a browser entry for config.browser but its executablePath is undefined/empty. BrowserExecutableNotFoundError extends McpBrowserError and carries a hint telling the user to verify the browser is installed or provide an explicit executablePath. The message interpolates the browser name.

Source

Thrown at packages/@n8n/mcp-browser/src/adapters/agent-browser.ts:184

				timeout: 5_000,
			});
		} catch {
			// no existing session — that's fine
		}
	}

	// =========================================================================
	// Lifecycle
	// =========================================================================

	async launch(config: ConnectConfig): Promise<void> {
		log.debug('launch: killing stale session');
		await this.killSession();
		log.debug('launch: stale session killed');

		const browserInfo = this.resolvedConfig.browsers.get(config.browser);
		const chromePath = browserInfo?.executablePath;
		if (!chromePath) throw new BrowserExecutableNotFoundError(config.browser);
		log.debug('launch: browser executable:', chromePath);

		if (!this.relay) {
			this.relay = new CDPRelayServer();
			this.relayPort = await this.relay.listen();
			log.debug('launch: relay listening on port', this.relayPort);
		} else {
			log.debug('launch: reusing existing relay on port', this.relayPort);
		}

		if (!this.relay.isExtensionConnected()) {
			const extensionEndpoint = this.relay.extensionEndpoint(this.relayPort);
			// `N8N_EVAL_AUTO_BROWSER_CONNECT=1` mirrors the playwright adapter — see
			// `playwright.ts` for the full justification. The extension only honors
			// the flag when the relay URL is localhost, which it always is here.
			const autoConnect = process.env.N8N_EVAL_AUTO_BROWSER_CONNECT === '1';
			const connectUrl =
				`chrome-extension://${BROWSER_USE_EXTENSION_ID}/connect.html` +

View on GitHub (pinned to 5ac6606e81)

Solutions

  1. Provide an explicit executablePath in the browser config for the browser you are selecting.
  2. Re-run browser detection so the config reflects currently-installed browsers.
  3. Verify the browser is actually installed: run the binary path from a shell.
  4. If config.browser is wrong, pass the name of a browser that IS in resolvedConfig.browsers.

Example fix

// before — relying on auto-detection that returned no path
await adapter.launch({ browser: 'chrome' });

// after — set executablePath explicitly
const config = buildConfig({
  browsers: { chrome: { executablePath: '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome' } },
});
await adapter.launch({ browser: 'chrome' });
Defensive patterns

Strategy: validation

Validate before calling

function hasExecutablePath(config: ResolvedConfig, browser: string): boolean {
  return !!config.browsers.get(browser)?.executablePath;
}

Type guard

function isBrowserExecutableAvailable(config: ResolvedConfig, browser: string): boolean {
  return Boolean(config.browsers.get(browser)?.executablePath);
}

Prevention

When it happens

Trigger: Calling adapter.launch(config) where resolvedConfig.browsers.get(config.browser) returns an object with no executablePath, or returns undefined (so browserInfo?.executablePath is undefined). The browser was either not detected at all or detected without resolving a binary path.

Common situations: Chrome/Chromium/Brave/Edge was uninstalled after the config was built; the browser detection ran in a different environment (Docker vs host) and the path is stale; the browser is installed but not in a standard location the detector scans; config.browser names a browser that isn't in the resolved browsers map.

Related errors


AI-assisted analysis of n8n-io/n8n@5ac6606e81 (2026-08-12). Data as JSON: /api/errors/d8a68b793179bad0. Report an issue: GitHub.