{"record":{"id":"d6a3c67e0f27db08","repo":"garrytan/gstack","slug":"invalid-file-url-file-would-list-the-home-di","errorCode":null,"errorMessage":"Invalid file URL: file://~/ would list the home directory. Use file://~/<filename> to render a specific file.","messagePattern":"Invalid file URL: file://~/ would list the home directory\\. Use file://~/<filename> to render a specific file\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"browse/src/url-validation.ts","lineNumber":174,"sourceCode":"    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);\n    const absPath = path.resolve(process.cwd(), rel);\n    return pathToFileURL(absPath).href + trailing;\n  }\n\n  // localhost host explicitly allowed: file://localhost/<abs> (pass through to standard parser).\n  if (afterDoubleSlash.toLowerCase().startsWith('localhost/')) {","sourceCodeStart":156,"sourceCodeEnd":192,"githubUrl":"https://github.com/garrytan/gstack/blob/94993f74012782fd94416dd44b8314f6363a13a4/browse/src/url-validation.ts#L156-L192","documentation":"Thrown by normalizeFileUrl when the input is `file://~` or `file://~/` — the file scheme with `~` as the authority and no filename. Like the `.` case, this would trigger a directory listing of the home directory, so the library demands an explicit filename.","triggerScenarios":"Calling goto with `file://~/` (trailing slash, no filename); building a URL as `file://~/${rest}` where rest is empty.","commonSituations":"A user trying to 'browse my home folder'; a fixture loader using `~` as a base and joining an empty filename; a docs example that trimmed the final path segment.","solutions":["Always include the filename: `file://~/Documents/report.html`.","When constructing from `~` + filename, default the filename if empty.","Prefer pathToFileURL(path.join(os.homedir(), filename)).href for programmatic construction."],"exampleFix":"// before\nawait goto(`file://~/${name}`); // name empty → file://~/\n// after\nconst file = name || 'index.html';\nawait goto(`file://~/${file}`);","handlingStrategy":"validation","validationCode":"function requireHomeFilename(u: string): void {\n  const lower = u.toLowerCase();\n  if (lower === 'file://~' || lower === 'file://~/') {\n    throw new Error('file://~/ requires a filename');\n  }\n}","typeGuard":"const hasHomeRelativeFilename = (u: string): boolean => {\n  const m = /^file:\\/\\/~\\/(.+)$/i.exec(u);\n  return !!m && m[1].length > 0;\n};","tryCatchPattern":"try {\n  await goto(url);\n} catch (e: any) {\n  if (/file:\\/~\\/ would list/.test(e.message)) {\n    await goto(`file://~/index.html`);\n  } else throw e;\n}","preventionTips":["Always join a filename onto the `file://~/` prefix.","Build home-relative URLs with pathToFileURL(path.join(os.homedir(), file)).href.","Default to index.html when the filename is missing.","Validate basename non-empty before constructing the URL."],"tags":["url-validation","file-url","directory-listing","home-relative"],"backgroundTag":null,"analyzedSha":"94993f74012782fd94416dd44b8314f6363a13a4","analyzedAt":"2026-08-12T04:06:23.140Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}