vitejs/vite · error · Error

Invalid glob: " " (resolved: " "). It must start with '/'…

Error message

Invalid glob: "${glob}" (resolved: "${resolved}"). It must start with '/' or './'

What it means

resolveGlobPattern normalizes a single glob. It accepts globs starting with '/', './', '../', or '**', and tries to resolve anything else as a module id. If that resolution does not produce an absolute path, the glob is unusable and Vite throws, echoing both the raw glob and the resolved value.

Solutions

  1. Prefix the glob with './' for relative imports or '/' for absolute-from-root.
  2. If importing from a package, install/verify the package so resolveId returns an absolute path.
  3. For '#' subpath imports ensure the target exports map resolves; otherwise switch to an explicit relative/absolute glob.
  4. Check the printed 'resolved' value in the error — if it equals the raw glob, resolution failed entirely.

Example fix

// before
const mods = import.meta.glob('src/widgets/*.vue')
// after
const mods = import.meta.glob('./widgets/*.vue')
// or
const mods = import.meta.glob('/src/widgets/*.vue')
Defensive patterns

Strategy: validation

Validate before calling

function validateGlob(glob) {
  if (glob.startsWith('/') || glob.startsWith('./') || glob.startsWith('../') || glob.startsWith('**')) return
  // bare spec: ensure it resolves
  // (caller checks resolveId result is absolute before passing on)
  throw new Error(`Glob must start with '/', './', '../', or '**': ${glob}`)
}

Type guard

function isWellFormedGlob(glob): boolean {
  return glob.startsWith('/') || glob.startsWith('./') || glob.startsWith('../') || glob.startsWith('**')
}

Prevention

When it happens

Trigger: Passing import.meta.glob a bare specifier (e.g. 'foo/*.js') or a path that neither matches the recognized prefixes nor resolves to an absolute module path. Also triggered by typos like 'src/x' (no leading './').

Common situations: Users assuming bare globs resolve like Node imports, copy-paste glob strings missing the './' prefix, or globs pointing at packages that are not installed (so resolveId returns the bare string unchanged, which is not absolute).

Related errors


AI-assisted analysis of vitejs/vite@b4d66fee14 (2026-08-11). Data as JSON: /api/errors/50f32a04a4dd9d1f. Report an issue: GitHub.

Appendix: source

Thrown at packages/vite/src/node/plugins/importMetaGlob.ts:687

  }

  if (glob[0] === '/') return pre + posix.join(root, glob.slice(1))
  if (glob.startsWith('./')) return pre + posix.join(dir, glob.slice(2))
  if (glob.startsWith('../')) return pre + posix.join(dir, glob)
  if (glob.startsWith('**')) return pre + glob

  const isSubImportsPattern = glob[0] === '#' && glob.includes('*')

  const resolved = normalizePath(
    (await resolveId(glob, importer, {
      custom: { 'vite:import-glob': { isSubImportsPattern } },
    })) || glob,
  )
  if (isAbsolute(resolved)) {
    return pre + globSafeResolvedPath(resolved, glob)
  }

  throw new Error(
    `Invalid glob: "${glob}" (resolved: "${resolved}"). It must start with '/' or './'`,
  )
}

export function getCommonBase(globsResolved: string[]): null | string {
  const bases = globsResolved
    .filter((g) => g[0] !== '!')
    .map((glob) => {
      let { base } = picomatch.scan(glob)
      // `scan('a/foo.js')` returns `base: 'a/foo.js'`
      if (posix.basename(base).includes('.')) base = posix.dirname(base)

      return base
    })

  if (!bases.length) return null

  let commonAncestor = ''

View on GitHub (pinned to b4d66fee14)