microsoft/playwright · error · Error
Access to "file:" protocol is blocked. Attempted URL: "${url
Error message
Access to "file:" protocol is blocked. Attempted URL: "${url}" What it means
Thrown by Context.checkUrlAllowed when a navigation/request targets a file: URL and the config flag allowUnrestrictedFileAccess is not set. The check is skipped entirely (returns early) when URL.canParse fails, but a well-formed file:// URL with the flag disabled is blocked to keep LLM-driven navigation from touching the local filesystem.
Source
Thrown at packages/playwright-core/src/tools/backend/context.ts:349
await this._setupRequestInterception(browserContext);
for (const initScript of this.config.browser?.initScript || [])
this._disposables.push(await browserContext.addInitScript({ path: path.resolve(this.options.cwd, initScript) }));
for (const page of browserContext.pages())
this._onPageCreated(page);
this._disposables.push(eventsHelper.addEventListener(browserContext, 'page', page => this._onPageCreated(page)));
return browserContext;
}
checkUrlAllowed(url: string) {
if (this.config.allowUnrestrictedFileAccess)
return;
if (!URL.canParse(url))
return;
if (new URL(url).protocol === 'file:')
throw new Error(`Access to "file:" protocol is blocked. Attempted URL: "${url}"`);
}
lookupSecret(secretName: string): { value: string, code: string, isSecret: boolean } {
if (!this.config.secrets?.[secretName])
return { value: secretName, code: escapeWithQuotes(secretName, '\''), isSecret: false };
const codegen = this.config.codegen ?? 'typescript';
return {
value: this.config.secrets[secretName]!,
code: secretCode(codegen === 'none' ? 'typescript' : codegen, secretName),
isSecret: true,
};
}
redactSecrets(text: string): string {
for (const [secretName, secretValue] of Object.entries(this.config.secrets ?? {})) {
if (!secretValue)
continue;
text = text.replaceAll(secretValue, `<secret>${secretName}</secret>`);View on GitHub (pinned to c8fc3bf8d3)
Solutions
- Serve the file over http(s) (e.g. a local static server) and navigate to that URL instead.
- If local file access is intended and the trust boundary allows it, enable allowUnrestrictedFileAccess in the MCP/browser config.
- Rewrite the target so checkUrlAllowed sees an http(s) URL.
Example fix
// before
await page.goto('file:///home/user/report.html'); // throws via checkUrlAllowed
// after (option A - serve)
await page.goto('http://localhost:8080/report.html');
// after (option B - allow)
// context config: { allowUnrestrictedFileAccess: true } Defensive patterns
Strategy: validation
Validate before calling
function isAllowedUrl(url: string, allowFile = false): boolean {
if (!URL.canParse(url)) return true; // mirrors checkUrlAllowed early-out
const proto = new URL(url).protocol;
if (proto === 'file:') return allowFile;
return true;
}
if (!isAllowedUrl(target, !!config.allowUnrestrictedFileAccess)) {
throw new Error(`Refusing file: URL: ${target}`);
} Type guard
function isFileProtocol(url: string): boolean {
return URL.canParse(url) && new URL(url).protocol === 'file:';
} Try / catch
try {
await page.goto(target);
} catch (e) {
if (e instanceof Error && e.message.startsWith('Access to "file:" protocol is blocked')) {
// serve locally instead, or re-run with allowUnrestrictedFileAccess after user consent
} else throw e;
} Prevention
- Never pass file:// URLs to navigation tools unless the config explicitly allows it.
- Wrap local files in an http server when driving the browser via MCP.
- Centralize URL validation upstream so agents cannot reach checkUrlAllowed with a file URL.
When it happens
Trigger: Any navigation, goto, or request-initiating MCP tool called with a file:// URL while ContextConfig.allowUnrestrictedFileAccess is unset/false.
Common situations: MCP agent opening a locally generated HTML report; a test harness that tries to view file:// fixtures through the MCP browser; default config which ships with file access blocked for safety.
Related errors
- File access denied: ${resolvedFilename} is outside allowed r
- Execution context was destroyed, most likely because of a na
- Cannot navigate to "${url}": this page is not available in a
- Download filename '${downloadFilename}' escapes download dir
- "referer" is already specified as extra HTTP header
AI-assisted analysis of microsoft/playwright@c8fc3bf8d3 (2026-08-12).
Data as JSON: /api/errors/f3a199710b26af99.
Report an issue: GitHub.