n8n-io/n8n · warning

Invalid ${role}: argument cannot start with '-' (got: ${JSON

Error message

Invalid ${role}: argument cannot start with '-' (got: ${JSON.stringify(value.slice(0, 20))})

What it means

Thrown by AgentBrowserAdapter.assertSafeArg when a string argument (element target ref, selector, URL, key, or selector in wait) has length > 1 and starts with '-'. The guard exists because agent-browser's CLI scans ALL raw args for '--help'/'-h' before parsing, so any arg starting with '-' would be misinterpreted as a flag — a command-injection / arg-spoofing vector. The first 20 chars of the offending value are echoed in the error.

Source

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

		}
		if (tab.active) return;
		await this.run(['tab', tab.tabId]);
		for (const t of this.tabCache) t.active = t.tabId === pageId;
	}

	private resolveTarget(target: ElementTarget): string {
		const value =
			'ref' in target
				? target.ref.startsWith('@')
					? target.ref
					: `@${target.ref}`
				: target.selector;
		return AgentBrowserAdapter.assertSafeArg(value, 'element target');
	}

	private static assertSafeArg(value: string, role: string): string {
		if (value.length > 1 && value.startsWith('-')) {
			throw new Error(
				`Invalid ${role}: argument cannot start with '-' (got: ${JSON.stringify(value.slice(0, 20))})`,
			);
		}
		return value;
	}

	private async runAction(args: string[]): Promise<void> {
		const resp = await this.run(args);
		if (!resp.success) {
			throw new Error(resp.error ?? 'agent-browser action failed');
		}
	}

	private async navResult(pageId: string): Promise<NavigateResult> {
		const tabs = await this.refreshTabs();
		const tab = tabs.find((t) => t.tabId === pageId);
		return { title: tab?.title ?? '', url: tab?.url ?? '', status: 0 };
	}

View on GitHub (pinned to 5ac6606e81)

Solutions

  1. Rewrite the selector so it does not start with '-' — e.g. prefix with a tag or attribute selector: '[data-id="-foo"]' instead of '-foo'.
  2. For press(), pass key combinations without a leading dash; use 'Minus' for the '-' key itself if supported.
  3. If the value legitimately starts with '-', route through type() which peels leading dashes into separate calls.
  4. Sanitize model-emitted selectors before passing them to click/hover/scroll.

Example fix

// before — selector starts with '-' (rejected)
await adapter.click(pageId, { selector: '-moz-binding' });

// after — wrap so it no longer starts with '-'
await adapter.click(pageId, { selector: '[style*="-moz-binding"]' });
Defensive patterns

Strategy: validation

Validate before calling

function isSafeArg(value: string): boolean {
  return !(value.length > 1 && value.startsWith('-'));
}

Type guard

function isSafeAgentBrowserArg(value: string): boolean {
  return value.length <= 1 || !value.startsWith('-');
}

Prevention

When it happens

Trigger: Calling any adapter method that runs assertSafeArg with a value starting with '-': a CSS selector like '-webkit-foo', an aria ref that somehow starts with '-', a URL starting with '-' (malformed), or press() keys like '-Enter'. Also newPage(url) and navigate(url) which call assertSafeArg on the URL.

Common situations: A snapshot ref was malformed and starts with '-'; a custom CSS selector begins with a vendor prefix; the type() method already peels leading '-' chars but press/upload/scroll/newPage/navigate do not; a model emitted a selector starting with a dash.

Related errors


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