garrytan/gstack · error · Error
Invalid file URL: file:/// has no path. Use file:///<absolut
Error message
Invalid file URL: file:/// has no path. Use file:///<absolute-path>.
What it means
Thrown by normalizeFileUrl when the input is exactly `file:///` or `file:////` — the file scheme with three slashes and no path. These would normally fall through to Chromium's directory-listing behaviour for the filesystem root, which the library deliberately refuses so the caller must specify a concrete file.
Source
Thrown at browse/src/url-validation.ts:154
// Find the FIRST `?` or `#`, whichever comes first, and take everything
// after (including the delimiter) as the trailing segment.
const qIdx = url.indexOf('?');
const hIdx = url.indexOf('#');
let delimIdx = -1;
if (qIdx >= 0 && hIdx >= 0) delimIdx = Math.min(qIdx, hIdx);
else if (qIdx >= 0) delimIdx = qIdx;
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.');
}View on GitHub (pinned to 94993f7401)
Solutions
- Append a concrete absolute path: `file:///tmp/index.html`.
- When templating, default to a known index file if the path is empty: `${base}index.html`.
- Use pathToFileURL(absPath).href to construct file URLs from a path string so the slash count is always correct.
Example fix
// before
const url = `file://${dir}/`; // → 'file:///tmp/x/' or worse
// after
const url = require('url').pathToFileURL(require('path').join(dir, 'index.html')).href; Defensive patterns
Strategy: validation
Validate before calling
const { pathToFileURL } = require('url');
const path = require('path');
function safeFileUrl(p: string): string {
if (!p) throw new Error('Invalid file URL: file:/// has no path.');
return pathToFileURL(path.resolve(p)).href;
} Type guard
const hasNonEmptyPath = (u: string): boolean => /^file:\/\/\/.+/.test(u) && u !== 'file:////';
Try / catch
try {
await goto(url);
} catch (e: any) {
if (/file:\/\/ has no path/.test(e.message)) {
await goto(pathToFileURL(path.resolve(defaultIndex)).href);
} else throw e;
} Prevention
- Build file URLs with pathToFileURL(absPath).href — never string concat.
- Default empty paths to a known index file before building the URL.
- Validate the basename is non-empty at the caller boundary.
- Avoid trailing slashes in fixture paths.
When it happens
Trigger: Calling goto/validateNavigationUrl with `file:///`, `file:////`, or programmatically concatenating `file://` + a path that turns out empty.
Common situations: A test fixture that builds `file://${process.cwd()}/` and forgets the filename; templating that strips empty path segments; a CLI user typing `browse goto file:///` expecting a 'home' view.
Related errors
- Invalid file URL: ${url}. Use file:///<absolute-path> or fil
- 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/d4bcf62865d1f461.
Report an issue: GitHub.