google-gemini/gemini-cli · error · DomainNotAllowedError
Domain not allowed: The requested domain is not in the…
Error message
Domain not allowed: The requested domain is not in the allowed list.
What it means
Thrown as DomainNotAllowedError from callTool() when checkNavigationRestrictions returns a non-empty message. It fires for navigate_page / new_page when the target URL's hostname (or an http/https URL embedded in query params or fragment) is not matched by any entry in customConfig.allowedDomains. The error class is caught by mcpToolWrapper to terminate the agent run.
Solutions
- Add the required hostname (or a *.domain wildcard) to customConfig.allowedDomains.
- If using a wildcard *.example.com and the apex is needed, also add 'example.com' explicitly (isDomainAllowed only matches base or *.base subdomains for wildcards).
- Drop the allowedDomains config entirely if domain restriction is not required.
- Avoid embedding off-domain URLs in query parameters of allowed-domain URLs.
Example fix
// before allowedDomains: ['*.example.com'] // navigating to https://example.com (apex) -> blocked // after: include the apex explicitly allowedDomains: ['example.com', '*.example.com']
Defensive patterns
Strategy: type-guard
Validate before calling
function isAllowed(hostname, allowed) {
const h = hostname.replace(/\.$/, '');
return allowed.some(p =>
p.startsWith('*.') ? h === p.slice(2) || h.endsWith('.' + p.slice(2)) : h === p
);
}
// Pre-check navigation targets:
function checkUrl(url, allowed) {
const host = new URL(url).hostname;
if (!isAllowed(host, allowed)) throw new Error('Domain not allowed: ' + host);
} Type guard
import { DomainNotAllowedError } from './browserManager.js';
function isDomainNotAllowed(e) {
return e instanceof DomainNotAllowedError ||
(e instanceof Error && e.name === 'DomainNotAllowedError');
} Try / catch
try {
await bm.callTool('navigate_page', { url });
} catch (e) {
if (e instanceof DomainNotAllowedError) {
// add host to allowedDomains or pick an allowed URL
}
throw e;
} Prevention
- Include both apex and wildcard in allowedDomains when needed.
- Validate target URLs against the allowlist before invoking navigate_page/new_page.
- Avoid embedding off-domain URLs in query parameters.
When it happens
Trigger: callTool('navigate_page', { url: 'https://blocked.example' }) (or 'new_page') when allowedDomains is configured and the hostname is not in it; also when a query/fragment parameter contains a URL to a disallowed host (proxy/translate bypass attempt).
Common situations: allowedDomains allowlist is narrow and the agent legitimately needs a sibling subdomain not covered; wildcard pattern misconfigured (e.g. *.example.com does not match example.com itself per isDomainAllowed); agent follows a redirect or embedded link outside the allowlist; user expects wildcards to cover the apex domain.
Related errors
- Invalid domain in allowedDomains
- Cannot launch a concurrent browser agent in
- Gemini CLI is not running in a trusted directory. To…
- Invalid regex pattern in allowedExtensions setting
- Workspace path is outside the allowed root directory
AI-assisted analysis of google-gemini/gemini-cli@5024443c72 (2026-08-12).
Data as JSON: /api/errors/a783dfa09a19f48a.
Report an issue: GitHub.
Appendix: source
Thrown at packages/core/src/agents/browser/browserManager.ts:345
if (signal?.aborted) {
throw signal.reason ?? new Error('Operation cancelled');
}
// Hard enforcement of per-action rate limit
if (!isInternal) {
if (this.actionCounter >= this.maxActionsPerTask) {
const error = new Error(
`Browser agent reached maximum action limit (${this.maxActionsPerTask}). ` +
`Task terminated to prevent runaway execution. To config the limit, use maxActionsPerTask in the settings.`,
);
throw error;
}
this.actionCounter++;
}
const errorMessage = this.checkNavigationRestrictions(toolName, args);
if (errorMessage) {
throw new DomainNotAllowedError(errorMessage);
}
const client = await this.getRawMcpClient();
const callPromise = client.callTool(
{ name: toolName, arguments: args },
undefined,
{ timeout: MCP_TIMEOUT_MS },
);
let result: McpToolCallResult;
// If no signal, just await directly
if (!signal) {
result = this.toResult(await callPromise);
} else {
// Race the call against the abort signal
let onAbort: (() => void) | undefined;
try {View on GitHub (pinned to 5024443c72)