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
- Rewrite the selector so it does not start with '-' — e.g. prefix with a tag or attribute selector: '[data-id="-foo"]' instead of '-foo'.
- For press(), pass key combinations without a leading dash; use 'Minus' for the '-' key itself if supported.
- If the value legitimately starts with '-', route through type() which peels leading dashes into separate calls.
- 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
- Sanitize model-emitted selectors/refs to not start with '-' before passing to click/hover/press/newPage.
- For values that legitimately start with '-', route through type() which peels leading dashes.
- Wrap selectors starting with a vendor prefix in an attribute selector like [style*="-moz-..."].
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
- Invalid skill at ${sourceDirectory}: ${errors.join('; ')}
- Webhook URL must use HTTPS. Got: ${url.protocol}
- Webhook URL cannot target localhost
- Webhook URL cannot target private/internal IP addresses
- Webhook URL cannot target internal hostname: ${hostname}
AI-assisted analysis of n8n-io/n8n@5ac6606e81 (2026-08-12).
Data as JSON: /api/errors/bb58194abe1adb1a.
Report an issue: GitHub.