{"record":{"id":"226b711cbe5dc4c3","repo":"garrytan/gstack","slug":"invalid-file-url-file-would-list-the-current","errorCode":null,"errorMessage":"Invalid file URL: file://./ would list the current directory. Use file://./<filename> to render a specific file.","messagePattern":"Invalid file URL: file://\\./ would list the current directory\\. Use file://\\./<filename> to render a specific file\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"browse/src/url-validation.ts","lineNumber":171,"sourceCode":"    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);\n    const absPath = path.resolve(process.cwd(), rel);\n    return pathToFileURL(absPath).href + trailing;\n  }","sourceCodeStart":153,"sourceCodeEnd":189,"githubUrl":"https://github.com/garrytan/gstack/blob/94993f74012782fd94416dd44b8314f6363a13a4/browse/src/url-validation.ts#L153-L189","documentation":"Thrown by normalizeFileUrl when the input is `file://.` or `file://./` — the file scheme with `.` as the authority. These would make Chromium list the current working directory, which is a different product surface and a potential information leak, so the library demands an explicit filename.","triggerScenarios":"Calling goto with `file://./` (trailing slash, no filename); building a URL as `file://${rel}/` where rel is `.`; auto-completing a path with a trailing slash.","commonSituations":"A user trying to 'open the current folder'; a fixture loader that joins `./` + '' when no fixture name is provided; IDE tab-completion inserting a trailing slash.","solutions":["Always include the filename: `file://./index.html`.","When constructing from a directory + filename, default the filename to 'index.html' if empty.","Validate that the joined path has a non-empty basename before building the URL."],"exampleFix":"// before\nawait goto(`file://./${name}/`); // name empty → file://./\n// after\nconst file = name || 'index.html';\nawait goto(`file://./${file}`);","handlingStrategy":"validation","validationCode":"function requireFileFilename(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 hasCwdRelativeFilename = (u: string): boolean => {\n  const m = /^file:\\/\\/(\\.\\/)?(.+)$/i.exec(u);\n  return !!m && m[2].length > 0 && m[2] !== '/';\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.","Default to index.html when the filename is missing.","Strip trailing slashes from user input before constructing the URL.","Validate basename non-empty at the caller boundary."],"tags":["url-validation","file-url","directory-listing","cwd-relative"],"backgroundTag":null,"analyzedSha":"94993f74012782fd94416dd44b8314f6363a13a4","analyzedAt":"2026-08-12T04:06:23.140Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}