{"record":{"id":"d3687c15a58126dc","repo":"garrytan/gstack","slug":"invalid-file-url-file-is-empty-use-file-a","errorCode":null,"errorMessage":"Invalid file URL: file:// is empty. Use file:///<absolute-path>.","messagePattern":"Invalid file URL: file:// is empty\\. Use file:///<absolute-path>\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"browse/src/url-validation.ts","lineNumber":168,"sourceCode":"  // file:/// or longer → standard absolute; pass through unchanged (caller validates path).\n  if (rest.startsWith('///')) {\n    // Reject bare root-only (file:/// with nothing after)\n    if (rest === '///' || rest === '////') {\n      throw new Error('Invalid file URL: file:/// has no path. Use file:///<absolute-path>.');\n    }\n    return pathPart + trailing;\n  }\n\n  // Everything else: must start with // (we accept file://... only)\n  if (!rest.startsWith('//')) {\n    throw new Error(`Invalid file URL: ${url}. Use file:///<absolute-path> or file://./<rel> or file://~/<rel>.`);\n  }\n\n  const afterDoubleSlash = rest.slice(2);\n\n  // Reject empty (file://) and trailing-slash-only (file://./ listing cwd).\n  if (afterDoubleSlash === '') {\n    throw new Error('Invalid file URL: file:// is empty. Use file:///<absolute-path>.');\n  }\n  if (afterDoubleSlash === '.' || afterDoubleSlash === './') {\n    throw new Error('Invalid file URL: file://./ would list the current directory. Use file://./<filename> to render a specific file.');\n  }\n  if (afterDoubleSlash === '~' || afterDoubleSlash === '~/') {\n    throw new Error('Invalid file URL: file://~/ would list the home directory. Use file://~/<filename> to render a specific file.');\n  }\n\n  // Home-relative: file://~/<rel>\n  if (afterDoubleSlash.startsWith('~/')) {\n    const rel = afterDoubleSlash.slice(2);\n    const absPath = path.join(os.homedir(), rel);\n    return pathToFileURL(absPath).href + trailing;\n  }\n\n  // cwd-relative with explicit ./ : file://./<rel>\n  if (afterDoubleSlash.startsWith('./')) {\n    const rel = afterDoubleSlash.slice(2);","sourceCodeStart":150,"sourceCodeEnd":186,"githubUrl":"https://github.com/garrytan/gstack/blob/94993f74012782fd94416dd44b8314f6363a13a4/browse/src/url-validation.ts#L150-L186","documentation":"Thrown by normalizeFileUrl when the input is exactly `file://` — the scheme plus authority separator and nothing else. With no path and no host the URL is empty and would resolve to a directory listing of the cwd, which the library refuses so the caller must specify a concrete file.","triggerScenarios":"Calling goto with the literal string `file://`; building a URL by concatenating `file://` + '' + nothing else; trimming a path down to nothing before joining.","commonSituations":"A template like `file://${host}` where host is empty; a CLI flag that takes an optional file path and the user supplied none; a copy-paste that dropped the path segment.","solutions":["Supply a concrete file: `file:///tmp/index.html`.","Use pathToFileURL on an absolute path so the slash count and path are always present.","Reject empty paths at the caller boundary before constructing the URL."],"exampleFix":"// before\nawait goto(`file://${maybePath}`); // maybePath === ''\n// after\nif (!maybePath) throw new Error('path required');\nawait goto(pathToFileURL(path.resolve(maybePath)).href);","handlingStrategy":"validation","validationCode":"function requireNonEmptyFileUrl(u: string): void {\n  if (u.toLowerCase() === 'file://') {\n    throw new Error('Invalid file URL: file:// is empty. Use file:///<absolute-path>.');\n  }\n}","typeGuard":"const isNonEmptyFileUrl = (u: string): boolean =>\n  u.toLowerCase() !== 'file://' && u.toLowerCase().startsWith('file:');","tryCatchPattern":"try {\n  await goto(url);\n} catch (e: any) {\n  if (/file:\\/\\/ is empty/.test(e.message)) {\n    await goto(pathToFileURL(path.resolve('index.html')).href);\n  } else throw e;\n}","preventionTips":["Reject empty path input before constructing the URL.","Build file URLs from concrete paths with pathToFileURL.","Treat an empty user input as a caller-side error, not a default-to-cwd.","Add a unit test for the empty-string case in your URL builder."],"tags":["url-validation","file-url","empty-input","navigation"],"backgroundTag":null,"analyzedSha":"94993f74012782fd94416dd44b8314f6363a13a4","analyzedAt":"2026-08-12T04:06:23.140Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}