vitejs/vite · error · Error
In virtual modules, all globs must start with '/'
Error message
In virtual modules, all globs must start with '/'
What it means
import.meta.glob globs are resolved relative to the importing module's directory. Virtual modules have no real file directory (dir is falsy), so a relative glob (./foo, ../foo) cannot be resolved. Vite requires absolute globs (starting with '/') when there is no dir, optionally combined with options.base.
Solutions
- Use absolute globs from project root in the virtual module: import.meta.glob('/src/routes/*.js').
- Pass options.base so Vite can resolve relative globs against it: import.meta.glob('./routes/*.js', { base: '/src' }).
- Move the glob call out of the virtual module into a real file and have the virtual module import that file.
- If you control the plugin, compute absolute paths at generation time instead of relying on relative resolution.
Example fix
// before (inside a virtual module)
const routes = import.meta.glob('./routes/*.js')
// after
const routes = import.meta.glob('/src/routes/*.js')
// or
const routes = import.meta.glob('./routes/*.js', { base: '/src' }) Defensive patterns
Strategy: validation
Validate before calling
// In virtual modules, force absolute globs
function safeGlob(glob, isVirtual, base) {
if (isVirtual && (glob.startsWith('./') || glob.startsWith('../')) && !base) {
throw new Error(`Virtual glob must be absolute: ${glob}`)
}
return glob
} Type guard
function isAbsoluteGlob(glob): boolean {
return glob.startsWith('/') || glob.startsWith('**')
} Prevention
- In virtual modules, always use globs starting with '/' or pass options.base.
- Centralize glob calls in real files when possible.
- Document for plugin users that virtual contexts require absolute globs.
When it happens
Trigger: Calling import.meta.glob with a relative pattern from inside a virtual module (a module id that is not a real file, e.g. a plugin-generated module with no file path), where isRelative is true and no options.base is supplied.
Common situations: A plugin generates a virtual entry and that virtual code calls import.meta.glob('./routes/*.js'). Framework integrations that inject virtual modules containing glob calls hit this.
Related errors
- Invalid glob: " " (resolved: " "). It must start with '/'…
- `input` cannot contain glob characters. They are reserved…
- [module runner] "import.meta.glob" is statically replaced…
AI-assisted analysis of vitejs/vite@b4d66fee14 (2026-08-11).
Data as JSON: /api/errors/9e7dc82f8fa20fe1.
Report an issue: GitHub.
Appendix: source
Thrown at packages/vite/src/node/plugins/importMetaGlob.ts:457
if (!matches.length) return null
const s = new MagicString(code)
const staticImports = (
await Promise.all(
matches.map(
async ({
globsResolved,
isRelative,
options,
index,
start,
end,
onlyKeys,
onlyValues,
}) => {
if (!dir && !options.base && isRelative) {
throw new Error("In virtual modules, all globs must start with '/'")
}
const cwd = getCommonBase(globsResolved) ?? root
const files = (
await glob(globsResolved, {
absolute: true,
cwd,
dot: !!options.exhaustive,
expandDirectories: false,
caseSensitiveMatch: options.caseSensitive ?? true,
ignore: options.exhaustive ? [] : ['**/node_modules/**'],
extglob: false,
})
)
.filter((file) => file !== id)
.sort()
const objectProps: string[] = []View on GitHub (pinned to b4d66fee14)