garrytan/gstack · error · Error
Invalid file URL: ${url}. Use file:///<absolute-path> or fil
Error message
Invalid file URL: ${url}. Use file:///<absolute-path> or file://./<rel> or file://~/<rel>. What it means
Thrown by normalizeFileUrl when the input starts with `file:` but the remainder does not begin with `//` (so it is not a valid RFC 8089 authority-and-path form). Catches malformed shapes like `file:path`, `file:/path` (single slash), and `file:./x` that the standard URL parser would misinterpret.
Source
Thrown at browse/src/url-validation.ts:161
else if (hIdx >= 0) delimIdx = hIdx;
const pathPart = delimIdx >= 0 ? url.slice(0, delimIdx) : url;
const trailing = delimIdx >= 0 ? url.slice(delimIdx) : '';
const rest = pathPart.slice('file:'.length);
// file:/// or longer → standard absolute; pass through unchanged (caller validates path).
if (rest.startsWith('///')) {
// Reject bare root-only (file:/// with nothing after)
if (rest === '///' || rest === '////') {
throw new Error('Invalid file URL: file:/// has no path. Use file:///<absolute-path>.');
}
return pathPart + trailing;
}
// Everything else: must start with // (we accept file://... only)
if (!rest.startsWith('//')) {
throw new Error(`Invalid file URL: ${url}. Use file:///<absolute-path> or file://./<rel> or file://~/<rel>.`);
}
const afterDoubleSlash = rest.slice(2);
// Reject empty (file://) and trailing-slash-only (file://./ listing cwd).
if (afterDoubleSlash === '') {
throw new Error('Invalid file URL: file:// is empty. Use file:///<absolute-path>.');
}
if (afterDoubleSlash === '.' || afterDoubleSlash === './') {
throw new Error('Invalid file URL: file://./ would list the current directory. Use file://./<filename> to render a specific file.');
}
if (afterDoubleSlash === '~' || afterDoubleSlash === '~/') {
throw new Error('Invalid file URL: file://~/ would list the home directory. Use file://~/<filename> to render a specific file.');
}
// Home-relative: file://~/<rel>
if (afterDoubleSlash.startsWith('~/')) {
const rel = afterDoubleSlash.slice(2);View on GitHub (pinned to 94993f7401)
Solutions
- Always use the form `file:///<absolute-path>` (three slashes for Unix absolute paths).
- Build file URLs from paths with `require('url').pathToFileURL(absPath).href` — never by string concatenation.
- For relative paths use the supported shorthands `file://./<rel>` or `file://~/<rel>`.
Example fix
// before
await goto(`file:${absPath}`); // missing //
// after
const { pathToFileURL } = require('url');
await goto(pathToFileURL(absPath).href); Defensive patterns
Strategy: validation
Validate before calling
const { pathToFileURL } = require('url');
const path = require('path');
function fileUrlFromPath(p: string): string {
return pathToFileURL(path.resolve(p)).href;
} Type guard
const isRfc8089AuthorityForm = (u: string): boolean => /^file:\/\/(\/|\.|~|localhost\/).*/.test(u.toLowerCase());
Try / catch
try {
await goto(url);
} catch (e: any) {
if (/^Invalid file URL:.*Use file:\/\/\//.test(e.message)) {
await goto(pathToFileURL(path.resolve(url.replace(/^file:/, ''))).href);
} else throw e;
} Prevention
- Never build file URLs by string concatenation — always pathToFileURL.
- Require three slashes for absolute paths, two slashes + host/path for the supported shorthands.
- Reject Windows backslash paths at the boundary and convert with pathToFileURL.
- Add a fixture-URL builder helper so the slash count is centralized.
When it happens
Trigger: Calling goto with `file:/etc/hosts` (one slash), `file:index.html`, or hand-built strings that omitted the second slash.
Common situations: Concatenating `file:` + absolute filesystem path without the `//` authority prefix; copy-pasting a Windows path `file:C:\x`; templating that uses `file:${process.platform === 'win32' ? '/' : '//'}` and gets the branch wrong.
Related errors
- Invalid file URL: file:/// has no path. Use file:///<absolut
- Invalid file URL: file:// is empty. Use file:///<absolute-pa
- Invalid file URL: file://./ would list the current directory
- Invalid file URL: file://~/ would list the home directory. U
- Unsupported file URL host: ${segment}. Use file:///<absolute
AI-assisted analysis of garrytan/gstack@94993f7401 (2026-08-12).
Data as JSON: /api/errors/453d8e1d021ff6e4.
Report an issue: GitHub.